From 1e56cfc237b5c8187774d5574ac62087959c4e27 Mon Sep 17 00:00:00 2001 From: mbs Date: Wed, 13 Nov 2024 09:35:20 +0000 Subject: [PATCH] [bos #43130] [EDF] (2024) Geometry Analysis Tool --- CMakeLists.txt | 13 +- doc/salome/examples/check_bop.py | 56 +++ doc/salome/examples/tests.set | 2 + doc/salome/gui/GEOM/input/check_bop.doc | 32 ++ doc/salome/gui/GEOM/input/tui_check_bop.doc | 6 + .../gui/GEOM/input/tui_measurement_tools.doc | 1 + .../GEOM/input/using_measurement_tools.doc | 1 + idl/GEOM_Gen.idl | 19 + src/AdvancedEngine/CMakeLists.txt | 1 + src/BREPPlugin/CMakeLists.txt | 1 + src/GEOMImpl/CMakeLists.txt | 2 + src/GEOMImpl/GEOMImpl_IMeasureOperations.cxx | 293 ++++++------- src/GEOMImpl/GEOMImpl_IMeasureOperations.hxx | 41 +- src/GEOMImpl/GEOMImpl_PartitionDriver.cxx | 3 + src/GEOMImpl/GEOMImpl_Types.hxx | 1 + src/GEOM_I/CMakeLists.txt | 2 + src/GEOM_I/GEOM_IMeasureOperations_i.cc | 75 +++- src/GEOM_I/GEOM_IMeasureOperations_i.hh | 9 + src/GEOM_SWIG/geomBuilder.py | 92 ++++- src/IGESPlugin/CMakeLists.txt | 1 + src/STEPPlugin/CMakeLists.txt | 1 + src/STLPlugin/CMakeLists.txt | 1 + src/VTKPlugin/CMakeLists.txt | 1 + src/XAOPlugin/CMakeLists.txt | 1 + test/data/ExtractBOPFailure_compound1.brep | 388 ++++++++++++++++++ test/test_ExtractBOPFailure.py | 85 ++++ test/tests.set | 3 +- 27 files changed, 907 insertions(+), 224 deletions(-) create mode 100644 doc/salome/examples/check_bop.py create mode 100644 doc/salome/gui/GEOM/input/check_bop.doc create mode 100644 doc/salome/gui/GEOM/input/tui_check_bop.doc create mode 100644 test/data/ExtractBOPFailure_compound1.brep create mode 100755 test/test_ExtractBOPFailure.py diff --git a/CMakeLists.txt b/CMakeLists.txt index cee851a22..47c7d2abc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -140,6 +140,13 @@ ENDIF(SALOME_BUILD_GUI) FIND_PACKAGE(SalomeOpenCASCADE REQUIRED) +SET(CommonGeomLib_ROOT_DIR $ENV{CommonGeomLib_ROOT_DIR} CACHE PATH "Path to the CommonGeomLib tool") +IF(EXISTS ${CommonGeomLib_ROOT_DIR}) + FIND_PACKAGE(SalomeCommonGeomLib REQUIRED) +ELSE(EXISTS ${CommonGeomLib_ROOT_DIR}) + MESSAGE(FATAL_ERROR "We absolutely need the CommonGeomLib tool, please define CommonGeomLib_ROOT_DIR !") +ENDIF(EXISTS ${CommonGeomLib_ROOT_DIR}) + IF(SALOME_GEOM_USE_VTK) FIND_PACKAGE(SalomeVTK REQUIRED) ADD_DEFINITIONS(-DWITH_VTK) @@ -279,19 +286,21 @@ EXPORT(TARGETS ${_${PROJECT_NAME}_exposed_targets} SET(KERNEL_ROOT_DIR "${KERNEL_ROOT_DIR}") SET(GUI_ROOT_DIR "${GUI_ROOT_DIR}") SET(OPENCASCADE_ROOT_DIR "${OPENCASCADE_ROOT_DIR}") +SET(CommonGeomLib_ROOT_DIR "${CommonGeomLib_ROOT_DIR}") SET(VTK_ROOT_DIR "${VTK_ROOT_DIR}") SET(OPENCV_ROOT_DIR "${OPENCV_ROOT_DIR}") SET(CONF_INCLUDE_DIRS "${PROJECT_SOURCE_DIR}/include" "${PROJECT_BINARY_DIR}/include") # Build variables that will be expanded when configuring SalomeConfig.cmake: -SALOME_CONFIGURE_PREPARE(OpenCV OpenCASCADE VTK) +SALOME_CONFIGURE_PREPARE(OpenCV OpenCASCADE CommonGeomLib VTK) CONFIGURE_PACKAGE_CONFIG_FILE(${PROJECT_NAME}Config.cmake.in ${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake INSTALL_DESTINATION "${SALOME_INSTALL_CMAKE_LOCAL}" PATH_VARS CONF_INCLUDE_DIRS SALOME_INSTALL_CMAKE_LOCAL CMAKE_INSTALL_PREFIX - KERNEL_ROOT_DIR GUI_ROOT_DIR OPENCASCADE_ROOT_DIR VTK_ROOT_DIR OPENCV_ROOT_DIR) + KERNEL_ROOT_DIR GUI_ROOT_DIR OPENCASCADE_ROOT_DIR CommonGeomLib_ROOT_DIR + VTK_ROOT_DIR OPENCV_ROOT_DIR) # - in the install tree (VSR 16/08/2013: TEMPORARILY COMMENT THIS - TO REMOVE?): # Get the relative path of the include directory so diff --git a/doc/salome/examples/check_bop.py b/doc/salome/examples/check_bop.py new file mode 100644 index 000000000..8dc915a96 --- /dev/null +++ b/doc/salome/examples/check_bop.py @@ -0,0 +1,56 @@ +# ExtractBOPFailure example + +import math +import salome +salome.salome_init() +import GEOM +from salome.geom import geomBuilder +geompy = geomBuilder.New() + +### Prepare shapes for Partition +OX = geompy.MakeVectorDXDYDZ(1, 0, 0, theName="OX") +OY = geompy.MakeVectorDXDYDZ(0, 1, 0, theName="OY") +OZ = geompy.MakeVectorDXDYDZ(0, 0, 1, theName="OZ") + +Vertex_1 = geompy.MakeVertex(0, 0, 0, theName="Vertex_1") +Vertex_2 = geompy.MakeVertex(10, 0, 0, theName="Vertex_2") +Vertex_3 = geompy.MakeVertex(0, 0.005, 0, theName="Vertex_3") +Vertex_4 = geompy.MakeVertex(10, 0.015, 0, theName="Vertex_4") +Vertex_5 = geompy.MakeVertex(0, 0.02, 0, theName="Vertex_5") +Vertex_6 = geompy.MakeVertex(10, 0.02, 0, theName="Vertex_6") + +Line_1 = geompy.MakeLineTwoPnt(Vertex_1, Vertex_2, theName="Line_1") +Line_2 = geompy.MakeLineTwoPnt(Vertex_3, Vertex_4, theName="Line_2") +Line_3 = geompy.MakeLineTwoPnt(Vertex_5, Vertex_6, theName="Line_3") + +Extrusion_1 = geompy.MakePrismVecH(Line_1, OY, 1, theName="Extrusion_1") +Extrusion_2 = geompy.MakePrismVecH(Line_2, OZ, 1, theName="Extrusion_2") +Extrusion_3 = geompy.MakePrismVecH(Line_3, OY, -1, theName="Extrusion_3") + +Limit_tolerance_1 = geompy.LimitTolerance(Extrusion_2, 0.01, theName="Limit_tolerance_1") + +Extrusion_4 = geompy.MakePrismVecH(Extrusion_1, OZ, -1, theName="Extrusion_4") +Extrusion_5 = geompy.MakePrismVecH(Extrusion_3, OZ, -1, theName="Extrusion_5") + +Revolution_1 = geompy.MakeRevolution(Limit_tolerance_1, OX, 45*math.pi/180.0, theName="Revolution_1") + +### Try Partition +try : + Partition_1 = geompy.MakePartition([Extrusion_4, Extrusion_5, Revolution_1], [], [], [], geompy.ShapeType["SOLID"], 0, [], 0, theName="Partition_1") +except : + print("EXCEPTION: Partition problem") + +### Extract failures +(IsValid, ShapeRes, ShapeErrors) = geompy.ExtractBOPFailure([Extrusion_4, Extrusion_5, Revolution_1], theTimer=True, theVerbose=True, theName="InvalidBOPResult") + +### Publish incriminated sub-shapes (reflect errors in their names) +for shapeError in ShapeErrors: + list_ids = shapeError.incriminated + list_subs = geompy.SubShapes(ShapeRes, list_ids) + ii = 1 + for subshape in list_subs: + geompy.addToStudyInFather( ShapeRes, subshape, 'SubShape_with_%s_%d'%(str(shapeError.error),ii) ) + ii = ii+1 + +if salome.sg.hasDesktop(): + salome.sg.updateObjBrowser() diff --git a/doc/salome/examples/tests.set b/doc/salome/examples/tests.set index 467f2029e..2aa159ada 100644 --- a/doc/salome/examples/tests.set +++ b/doc/salome/examples/tests.set @@ -58,6 +58,8 @@ SET(GOOD_TESTS check_compound_of_blocks.py check_self_intersections.py check_shape.py + check_conformity.py + check_bop.py complex_objs_ex01.py complex_objs_ex02.py complex_objs_ex03.py diff --git a/doc/salome/gui/GEOM/input/check_bop.doc b/doc/salome/gui/GEOM/input/check_bop.doc new file mode 100644 index 000000000..344b738fa --- /dev/null +++ b/doc/salome/gui/GEOM/input/check_bop.doc @@ -0,0 +1,32 @@ +/*! + +\page check_bop_page Extract BOP Failure + +The Extract BOP Failure tool makes it possible to analyse a BOP or Partition failure, in case the result is invalid. \n +It performs the general fuse BOP and returns the resulting shape and the list of errors from Check Shape point of view. + +This is a TUI-only functionality. + +TUI Command: + + +See also a \ref tui_check_bop_page "TUI example". + +*/ diff --git a/doc/salome/gui/GEOM/input/tui_check_bop.doc b/doc/salome/gui/GEOM/input/tui_check_bop.doc new file mode 100644 index 000000000..ea6c5e35f --- /dev/null +++ b/doc/salome/gui/GEOM/input/tui_check_bop.doc @@ -0,0 +1,6 @@ +/*! + +\page tui_check_bop_page Extract BOP Failure +\tui_script{check_bop.py} + +*/ diff --git a/doc/salome/gui/GEOM/input/tui_measurement_tools.doc b/doc/salome/gui/GEOM/input/tui_measurement_tools.doc index e0ce0be61..eb259f829 100644 --- a/doc/salome/gui/GEOM/input/tui_measurement_tools.doc +++ b/doc/salome/gui/GEOM/input/tui_measurement_tools.doc @@ -22,6 +22,7 @@
  • \subpage tui_check_self_intersections_fast_page
  • \subpage tui_fast_intersection_page
  • \subpage tui_check_conformity_page
  • +
  • \subpage tui_check_bop_page
  • \subpage tui_shape_proximity_page
  • \subpage tui_xyz_to_uv_page
  • \subpage tui_kind_of_shape_page
  • diff --git a/doc/salome/gui/GEOM/input/using_measurement_tools.doc b/doc/salome/gui/GEOM/input/using_measurement_tools.doc index c30850fd3..c9f89eceb 100644 --- a/doc/salome/gui/GEOM/input/using_measurement_tools.doc +++ b/doc/salome/gui/GEOM/input/using_measurement_tools.doc @@ -31,6 +31,7 @@
  • \subpage free_faces_page "Check Free Faces"
  • \subpage check_shape_page "Check Shape"
  • \subpage check_conformity_page "Check Conformity"
  • +
  • \subpage check_bop_page "Extract BOP Failures"
  • \subpage check_compound_of_blocks_page "Check compound of blocks"
  • \subpage get_non_blocks_page "Get non blocks"
  • \subpage check_self_intersections_page "Detect Self-intersections"
  • diff --git a/idl/GEOM_Gen.idl b/idl/GEOM_Gen.idl index 1d6abe8c3..7415e94a2 100644 --- a/idl/GEOM_Gen.idl +++ b/idl/GEOM_Gen.idl @@ -4797,6 +4797,25 @@ module GEOM string PrintShapeErrors (in GEOM_Object theShape, in ShapeErrors theErrors); + // /*! + // * \brief Extract and identify any problem in the source shapes used in a Boolean Operation. + // * \param theShapes Shapes being used in the Boolean Operation + // * \param theUseTimer Whether to chronometrize computation time + // * \param theTopoOnly Whether to check topology only + // * \param theRunParallel Whether to run the computations in parallel + // * \param theDoExact Whether to perform exact checking + // * \param theResultShape Output parameter. The result of BOP General Fuse. Indices of its sub-shapes are reported in theErrors structure. + // * \param theErrors Output parameter. Structure, containing discovered errors and incriminated sub-shapes. + // * \return TRUE, if the input shapes "seem to be valid" for BOP. + // */ + boolean ExtractBOPFailure (in ListOfGO theShapes, + in boolean theUseTimer, + in boolean theTopoOnly, + in boolean theRunParallel, + in boolean theDoExact, + out GEOM_Object theResultShape, + out ShapeErrors theErrors); + /*! * \brief Check a topology of the given shape on self-intersections presence. * \param theShape Shape to check validity of. diff --git a/src/AdvancedEngine/CMakeLists.txt b/src/AdvancedEngine/CMakeLists.txt index 156ed2fec..15a41a701 100644 --- a/src/AdvancedEngine/CMakeLists.txt +++ b/src/AdvancedEngine/CMakeLists.txt @@ -25,6 +25,7 @@ INCLUDE_DIRECTORIES( ${PTHREAD_INCLUDE_DIR} ${OpenCASCADE_INCLUDE_DIR} ${KERNEL_INCLUDE_DIRS} + ${CommonGeomLib_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/src/GEOMImpl ${PROJECT_SOURCE_DIR}/src/GEOM ${PROJECT_SOURCE_DIR}/src/GEOMAlgo diff --git a/src/BREPPlugin/CMakeLists.txt b/src/BREPPlugin/CMakeLists.txt index 385c9dcae..245454486 100644 --- a/src/BREPPlugin/CMakeLists.txt +++ b/src/BREPPlugin/CMakeLists.txt @@ -26,6 +26,7 @@ ENDIF() # additional include directories INCLUDE_DIRECTORIES( ${OpenCASCADE_INCLUDE_DIR} + ${CommonGeomLib_INCLUDE_DIRS} ${KERNEL_INCLUDE_DIRS} ${PROJECT_BINARY_DIR}/idl ${PROJECT_SOURCE_DIR}/src/GEOMAlgo diff --git a/src/GEOMImpl/CMakeLists.txt b/src/GEOMImpl/CMakeLists.txt index 64228aa7c..1cf8478d3 100644 --- a/src/GEOMImpl/CMakeLists.txt +++ b/src/GEOMImpl/CMakeLists.txt @@ -22,6 +22,7 @@ # additional include directories INCLUDE_DIRECTORIES( ${OpenCASCADE_INCLUDE_DIR} + ${CommonGeomLib_INCLUDE_DIRS} ${PTHREAD_INCLUDE_DIR} ${KERNEL_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS} @@ -46,6 +47,7 @@ ADD_DEFINITIONS( # libraries to link to SET(_link_LIBRARIES + ${CommonGeomLib_GeomAnaTool} ${OpenCASCADE_ModelingAlgorithms_LIBRARIES} ${PYTHON_LIBRARIES} ShHealOper GEOMbasic BlockFix GEOMAlgo GEOMUtils GEOMSketcher GEOMArchimede XAO diff --git a/src/GEOMImpl/GEOMImpl_IMeasureOperations.cxx b/src/GEOMImpl/GEOMImpl_IMeasureOperations.cxx index 56d5d592b..feac19765 100644 --- a/src/GEOMImpl/GEOMImpl_IMeasureOperations.cxx +++ b/src/GEOMImpl/GEOMImpl_IMeasureOperations.cxx @@ -34,6 +34,9 @@ #include #include +#include +#include + #include #include @@ -46,6 +49,10 @@ #include +// CommonGeomLib Includes +#include +#include + // OCCT Includes #include #include @@ -176,7 +183,7 @@ GEOMImpl_IMeasureOperations::ShapeKind GEOMImpl_IMeasureOperations::KindOfShape theDoubles->Append(aC.X()); theDoubles->Append(aC.Y()); theDoubles->Append(aC.Z()); - + gp_Dir aD = anAx3.XDirection(); theDoubles->Append(aD.X()); theDoubles->Append(aD.Y()); @@ -580,7 +587,7 @@ GEOMImpl_IMeasureOperations::ShapeKind GEOMImpl_IMeasureOperations::KindOfShape { // (+) geompy.kind.PLANAR xo yo zo dx dy dz nb_edges nb_vertices aKind = SK_PLANAR; - + theIntegers->Append(anInfo.NbSubShapes(TopAbs_EDGE)); theIntegers->Append(anInfo.NbSubShapes(TopAbs_VERTEX)); } @@ -1376,7 +1383,7 @@ Handle(GEOM_Object) GEOMImpl_IMeasureOperations::GetBoundingBox //Make a Python command GEOM::TPythonDump aPd(aFunction); - + aPd << aBnd << " = geompy.MakeBoundingBox(" << theShape; if (precise) { @@ -1460,7 +1467,7 @@ void GEOMImpl_IMeasureOperations::GetTolerance //============================================================================= bool GEOMImpl_IMeasureOperations::CheckShape (Handle(GEOM_Object) theShape, const Standard_Boolean theIsCheckGeom, - std::list &theErrors) + std::list &theErrors) { SetErrorCode(KO); theErrors.clear(); @@ -1484,7 +1491,7 @@ bool GEOMImpl_IMeasureOperations::CheckShape (Handle(GEOM_Object) theShape, if (ana.IsValid()) { isValid = true; } else { - FillErrors(ana, aShape, theErrors); + GeomAnaTool::FillErrors(ana, aShape, theErrors); } } catch (Standard_Failure& aFail) { @@ -1503,7 +1510,7 @@ bool GEOMImpl_IMeasureOperations::CheckShape (Handle(GEOM_Object) theShape, //============================================================================= TCollection_AsciiString GEOMImpl_IMeasureOperations::PrintShapeErrors (Handle(GEOM_Object) theShape, - const std::list &theErrors) + const std::list &theErrors) { TCollection_AsciiString aDump; @@ -1527,7 +1534,7 @@ TCollection_AsciiString GEOMImpl_IMeasureOperations::PrintShapeErrors if (!theErrors.empty()) { // The shape is not valid. Prepare errors for dump. TopTools_IndexedMapOfShape anIndices; - std::list::const_iterator anIter = theErrors.begin(); + std::list::const_iterator anIter = theErrors.begin(); Standard_Integer nbv, nbe, nbw, nbf, nbs, nbo; nbv = nbe = nbw = nbf = nbs = nbo = 0; @@ -1713,6 +1720,111 @@ TCollection_AsciiString GEOMImpl_IMeasureOperations::PrintShapeErrors return aDump; } + +//============================================================================= +/*! + * ExtractBOPFailure + */ +//============================================================================= +bool GEOMImpl_IMeasureOperations::ExtractBOPFailure + (const Handle(TColStd_HSequenceOfTransient)& theShapes, + const bool theUseTimer, + const bool theTopoOnly, + const bool theRunParallel, + const bool theDoExact, + Handle(GEOM_Object)& theResultShape, + std::list& theErrors) +{ + SetErrorCode(OK); + theErrors.clear(); + + if (theShapes.IsNull()) return false; + + Standard_Integer aNbShapes = theShapes->Length(); + if (!aNbShapes) return false; + + Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient; + + TopTools_ListOfShape aList; + for (int i = 1; i <= aNbShapes; i++) { + Handle(GEOM_Object) aGeomObj = Handle(GEOM_Object)::DownCast(theShapes->Value(i)); + if (aGeomObj.IsNull()) + continue; + + Handle(GEOM_Function) aRefShape = aGeomObj->GetLastFunction(); + if (aRefShape.IsNull()) + continue; + + TopoDS_Shape aShape = aRefShape->GetValue(); + if (aShape.IsNull()) + continue; + + aShapesSeq->Append(aRefShape); + aList.Append(aShape); + } + + // Call the GeomAnaTool API to extract BOP failures + bool isValid = false; + try + { + OCC_CATCH_SIGNALS; + GeomAnaTool_ExtractBOPFailure aTool (aList); + aTool.SetUseTimer(theUseTimer); + aTool.SetCheckGeometry(!theTopoOnly); // Either topo only or topo+geometry + aTool.SetRunParallel(theRunParallel); + aTool.SetExactCheck(theDoExact); + aTool.Perform(); + + // Check, if there are execution errors + const Handle(Message_Report) aReport = aTool.GetReport(); + Standard_SStream anOS; + aReport->Dump(anOS); + if (!anOS.str().empty()) { + SetErrorCode(anOS.str().c_str()); + if (aTool.HasFailureAlerts()) { + return false; + } + } + + TopoDS_Shape aShapeRes = aTool.Result(); + if (aShapeRes.IsNull()) { + return false; + } + + // Create Partition object. + theResultShape = GetEngine()->AddObject(GEOM_PARTITION); + Handle(GEOM_Function) aFunction = theResultShape->AddFunction + (GEOMImpl_PartitionDriver::GetID(), PARTITION_GENERAL_FUSE); + // For creation information filling + GEOMImpl_IPartition aCI (aFunction); + aCI.SetShapes(aShapesSeq); + // Set General Fuse result right here + // (without driver execution, as we already have the result shape) + aFunction->SetValue(aShapeRes); + + theErrors = aTool.ShapeErrors(); + isValid = theErrors.size() == 0; + + //Make a Python command + GEOM::TPythonDump aPD (aFunction); + aPD << "(isBOPFailure, " << theResultShape + << ", anErrors) = geompy.ExtractBOPFailure(["; + for (int i = 1; i <= aNbShapes; i++) { + aPD << Handle(GEOM_Object)::DownCast(theShapes->Value(i)); + if (i < aNbShapes) aPD << ", "; + } + aPD << "], " << theUseTimer << ", " << theTopoOnly + << ", " << theRunParallel << ", " << theDoExact << ")"; + } + catch(Standard_Failure& aFail) + { + SetErrorCode(aFail.GetMessageString()); + return false; + } + + return isValid; +} + //============================================================================= /*! * CheckSelfIntersections @@ -1832,11 +1944,11 @@ bool GEOMImpl_IMeasureOperations::CheckSelfIntersectionsFast // Launch the checker aTool.Perform(); - + const BRepExtrema_MapOfIntegerPackedMapOfInteger& intersections = aTool.OverlapElements(); - + std::set processed; - + for (BRepExtrema_MapOfIntegerPackedMapOfInteger::Iterator it(intersections); it.More(); it.Next()) { Standard_Integer idxLeft = it.Key(); if (processed.count(idxLeft) > 0) continue; // already added @@ -1954,14 +2066,14 @@ bool GEOMImpl_IMeasureOperations::FastIntersect (Handle(GEOM_Object) theShape1, // 1. Launch the checker aBSP.Perform(); - + // 2. Get sets of IDs of overlapped faces for (BRepExtrema_MapOfIntegerPackedMapOfInteger::Iterator anIt1 (aBSP.OverlapSubShapes1()); anIt1.More(); anIt1.Next()) { const TopoDS_Shape& aS1 = aBSP.GetSubShape1(anIt1.Key()); theIntersections1->Append(anIndices1.FindIndex(aS1)); } - + for (BRepExtrema_MapOfIntegerPackedMapOfInteger::Iterator anIt2 (aBSP.OverlapSubShapes2()); anIt2.More(); anIt2.Next()) { const TopoDS_Shape& aS2 = aBSP.GetSubShape2(anIt2.Key()); @@ -2330,7 +2442,7 @@ Standard_Integer GEOMImpl_IMeasureOperations::ClosestPoints (Handle(GEOM_Object) for (int i = 1; i <= nbSolutions; i++) { P1 = dst.PointOnShape1(i); P2 = dst.PointOnShape2(i); - + theDoubles->Append(P1.X()); theDoubles->Append(P1.Y()); theDoubles->Append(P1.Z()); @@ -3504,161 +3616,6 @@ double GEOMImpl_IMeasureOperations::ComputeTolerance(Handle(GEOM_Object) theEdge return aMaxDist; } -//======================================================================= -//function : FillErrorsSub -//purpose : Fill the errors list of subshapes on shape. -//======================================================================= -void GEOMImpl_IMeasureOperations::FillErrorsSub - (const BRepCheck_Analyzer &theAna, - const TopoDS_Shape &theShape, - const TopAbs_ShapeEnum theSubType, - TopTools_DataMapOfIntegerListOfShape &theMapErrors) const -{ - TopExp_Explorer anExp(theShape, theSubType); - TopTools_MapOfShape aMapSubShapes; - - for (; anExp.More(); anExp.Next()) { - const TopoDS_Shape &aSubShape = anExp.Current(); - - if (aMapSubShapes.Add(aSubShape)) { - const Handle(BRepCheck_Result) &aRes = theAna.Result(aSubShape); - - for (aRes->InitContextIterator(); - aRes->MoreShapeInContext(); - aRes->NextShapeInContext()) { - if (aRes->ContextualShape().IsSame(theShape)) { - BRepCheck_ListIteratorOfListOfStatus itl(aRes->StatusOnShape()); - - if (itl.Value() != BRepCheck_NoError) { - // Add all errors for theShape and its sub-shape. - for (;itl.More(); itl.Next()) { - const Standard_Integer aStat = (Standard_Integer)itl.Value(); - - if (!theMapErrors.IsBound(aStat)) { - TopTools_ListOfShape anEmpty; - - theMapErrors.Bind(aStat, anEmpty); - } - - TopTools_ListOfShape &theShapes = theMapErrors.ChangeFind(aStat); - - theShapes.Append(aSubShape); - theShapes.Append(theShape); - } - } - } - - break; - } - } - } -} - -//======================================================================= -//function : FillErrors -//purpose : Fill the errors list. -//======================================================================= -void GEOMImpl_IMeasureOperations::FillErrors - (const BRepCheck_Analyzer &theAna, - const TopoDS_Shape &theShape, - TopTools_DataMapOfIntegerListOfShape &theMapErrors, - TopTools_MapOfShape &theMapShapes) const -{ - if (theMapShapes.Add(theShape)) { - // Fill errors of child shapes. - for (TopoDS_Iterator iter(theShape); iter.More(); iter.Next()) { - FillErrors(theAna, iter.Value(), theMapErrors, theMapShapes); - } - - // Fill errors of theShape. - const Handle(BRepCheck_Result) &aRes = theAna.Result(theShape); - - if (!aRes.IsNull()) { - BRepCheck_ListIteratorOfListOfStatus itl(aRes->Status()); - - if (itl.Value() != BRepCheck_NoError) { - // Add all errors for theShape. - for (;itl.More(); itl.Next()) { - const Standard_Integer aStat = (Standard_Integer)itl.Value(); - - if (!theMapErrors.IsBound(aStat)) { - TopTools_ListOfShape anEmpty; - - theMapErrors.Bind(aStat, anEmpty); - } - - theMapErrors.ChangeFind(aStat).Append(theShape); - } - } - } - - // Add errors of subshapes on theShape. - const TopAbs_ShapeEnum aType = theShape.ShapeType(); - - switch (aType) { - case TopAbs_EDGE: - FillErrorsSub(theAna, theShape, TopAbs_VERTEX, theMapErrors); - break; - case TopAbs_FACE: - FillErrorsSub(theAna, theShape, TopAbs_WIRE, theMapErrors); - FillErrorsSub(theAna, theShape, TopAbs_EDGE, theMapErrors); - FillErrorsSub(theAna, theShape, TopAbs_VERTEX, theMapErrors); - break; - case TopAbs_SOLID: - FillErrorsSub(theAna, theShape, TopAbs_SHELL, theMapErrors); - break; - default: - break; - } - } -} - -//======================================================================= -//function : FillErrors -//purpose : Fill the errors list. -//======================================================================= -void GEOMImpl_IMeasureOperations::FillErrors - (const BRepCheck_Analyzer &theAna, - const TopoDS_Shape &theShape, - std::list &theErrors) const -{ - // Fill the errors map. - TopTools_DataMapOfIntegerListOfShape aMapErrors; - TopTools_MapOfShape aMapShapes; - - FillErrors(theAna, theShape, aMapErrors, aMapShapes); - - // Map sub-shapes and their indices - TopTools_IndexedMapOfShape anIndices; - - TopExp::MapShapes(theShape, anIndices); - - TopTools_DataMapIteratorOfDataMapOfIntegerListOfShape aMapIter(aMapErrors); - - for (; aMapIter.More(); aMapIter.Next()) { - ShapeError anError; - - anError.error = (BRepCheck_Status)aMapIter.Key(); - - TopTools_ListIteratorOfListOfShape aListIter(aMapIter.Value()); - TopTools_MapOfShape aMapUnique; - - for (; aListIter.More(); aListIter.Next()) { - const TopoDS_Shape &aShape = aListIter.Value(); - - if (aMapUnique.Add(aShape)) { - const Standard_Integer anIndex = anIndices.FindIndex(aShape); - - anError.incriminated.push_back(anIndex); - } - } - - if (!anError.incriminated.empty()) { - theErrors.push_back(anError); - } - } -} - //======================================================================= //function : ShapeProximityCalculator //purpose : returns an object to compute the proximity value diff --git a/src/GEOMImpl/GEOMImpl_IMeasureOperations.hxx b/src/GEOMImpl/GEOMImpl_IMeasureOperations.hxx index e13d8a5e7..c38c67f08 100644 --- a/src/GEOMImpl/GEOMImpl_IMeasureOperations.hxx +++ b/src/GEOMImpl/GEOMImpl_IMeasureOperations.hxx @@ -25,6 +25,8 @@ #include "GEOM_IOperations.hxx" +#include + #include #include #include @@ -149,30 +151,34 @@ class GEOMImpl_IMeasureOperations : public GEOM_IOperations { Standard_Real& EdgeMin, Standard_Real& EdgeMax, Standard_Real& VertMin, Standard_Real& VertMax); - struct ShapeError { - BRepCheck_Status error; - std::list incriminated; - }; - Standard_EXPORT bool CheckShape (Handle(GEOM_Object) theShape, const Standard_Boolean theIsCheckGeom, - std::list &theErrors); + std::list &theErrors); Standard_EXPORT TCollection_AsciiString PrintShapeErrors (Handle(GEOM_Object) theShape, - const std::list &theErrors); + const std::list &theErrors); + + Standard_EXPORT bool ExtractBOPFailure + (const Handle(TColStd_HSequenceOfTransient)& theShapes, + const bool theUseTimer, + const bool theTopoOnly, + const bool theRunParallel, + const bool theDoExact, + Handle(GEOM_Object)& theResultShape, + std::list& theErrors); Standard_EXPORT bool CheckSelfIntersections (Handle(GEOM_Object) theShape, const SICheckLevel theCheckLevel, Handle(TColStd_HSequenceOfInteger)& theIntersections); - + Standard_EXPORT bool CheckSelfIntersectionsFast (Handle(GEOM_Object) theShape, - float deflection, + float deflection, double tolerance, Handle(TColStd_HSequenceOfInteger)& theIntersections); Standard_EXPORT bool CheckBOPArguments (const Handle(GEOM_Object) &theShape); - + Standard_EXPORT bool FastIntersect (Handle(GEOM_Object) theShape1, Handle(GEOM_Object) theShape2, double tolerance, float deflection, Handle(TColStd_HSequenceOfInteger)& theIntersections1, @@ -271,21 +277,6 @@ class GEOMImpl_IMeasureOperations : public GEOM_IOperations { private: - void FillErrorsSub - (const BRepCheck_Analyzer &theAna, - const TopoDS_Shape &theShape, - const TopAbs_ShapeEnum theSubType, - TopTools_DataMapOfIntegerListOfShape &theMapErrors) const; - void FillErrors - (const BRepCheck_Analyzer &theAna, - const TopoDS_Shape &theShape, - TopTools_DataMapOfIntegerListOfShape &theMapErrors, - TopTools_MapOfShape &theMapShapes) const; - - void FillErrors (const BRepCheck_Analyzer &theAna, - const TopoDS_Shape &theShape, - std::list &theErrors) const; - Standard_Real getSurfaceCurvatures (const Handle(Geom_Surface)& aSurf, Standard_Real theUParam, Standard_Real theVParam, diff --git a/src/GEOMImpl/GEOMImpl_PartitionDriver.cxx b/src/GEOMImpl/GEOMImpl_PartitionDriver.cxx index 9bee2250f..b90dae0c5 100644 --- a/src/GEOMImpl/GEOMImpl_PartitionDriver.cxx +++ b/src/GEOMImpl/GEOMImpl_PartitionDriver.cxx @@ -564,6 +564,9 @@ GetCreationInformation(std::string& theOperationName, AddParam( theParams, "Object", aCI.GetShape() ); AddParam( theParams, "Plane", aCI.GetPlane() ); break; + case PARTITION_GENERAL_FUSE: + AddParam( theParams, "Objects", aCI.GetShapes() ); + break; default: return false; } diff --git a/src/GEOMImpl/GEOMImpl_Types.hxx b/src/GEOMImpl/GEOMImpl_Types.hxx index 9a0c75e65..044abaf85 100644 --- a/src/GEOMImpl/GEOMImpl_Types.hxx +++ b/src/GEOMImpl/GEOMImpl_Types.hxx @@ -268,6 +268,7 @@ #define PARTITION_PARTITION 1 #define PARTITION_HALF 2 #define PARTITION_NO_SELF_INTERSECTIONS 3 +#define PARTITION_GENERAL_FUSE 4 #define POLYLINE_POINTS 1 #define POLYLINE2D_PLN_COORDS 2 diff --git a/src/GEOM_I/CMakeLists.txt b/src/GEOM_I/CMakeLists.txt index 9cdacc9b6..9afdc0497 100644 --- a/src/GEOM_I/CMakeLists.txt +++ b/src/GEOM_I/CMakeLists.txt @@ -25,6 +25,7 @@ INCLUDE_DIRECTORIES( ${PTHREAD_INCLUDE_DIR} ${OpenCASCADE_INCLUDE_DIR} ${KERNEL_INCLUDE_DIRS} + ${CommonGeomLib_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/src/GEOMImpl ${PROJECT_SOURCE_DIR}/src/GEOM ${PROJECT_SOURCE_DIR}/src/GEOMAlgo @@ -47,6 +48,7 @@ ENDIF(WIN32) # libraries to link to SET(_link_LIBRARIES + ${CommonGeomLib_GeomAnaTool} GEOMImpl GEOMUtils SalomeIDLGEOM diff --git a/src/GEOM_I/GEOM_IMeasureOperations_i.cc b/src/GEOM_I/GEOM_IMeasureOperations_i.cc index 0acbdb36c..7a58c59fa 100644 --- a/src/GEOM_I/GEOM_IMeasureOperations_i.cc +++ b/src/GEOM_I/GEOM_IMeasureOperations_i.cc @@ -22,6 +22,7 @@ #include #include +#include #include "GEOM_IMeasureOperations_i.hh" @@ -42,7 +43,7 @@ */ static void ConvertShapeError (const GEOM::GEOM_IMeasureOperations::ShapeErrors &theErrorsFrom, - std::list &theErrorsTo) + std::list &theErrorsTo) { int aNbErr = theErrorsFrom.length(); int i = 0; @@ -51,7 +52,7 @@ static void ConvertShapeError const GEOM::GEOM_IMeasureOperations::ShapeError anErr = theErrorsFrom[i]; const GEOM::GEOM_IMeasureOperations::ShapeErrorType aType = anErr.error; const GEOM::ListOfLong anIncrims = anErr.incriminated; - GEOMImpl_IMeasureOperations::ShapeError anErrStruct; + GeomAnaTool::ShapeError anErrStruct; switch (aType) { case GEOM::GEOM_IMeasureOperations::InvalidPointOnCurve: @@ -176,7 +177,7 @@ static void ConvertShapeError * \param theErrorsTo result errors. */ static void ConvertShapeError - (const std::list &theErrorsFrom, + (const std::list &theErrorsFrom, GEOM::GEOM_IMeasureOperations::ShapeErrors_out &theErrorsTo) { const int aNbErr = theErrorsFrom.size(); @@ -186,7 +187,7 @@ static void ConvertShapeError anErrArray->length(aNbErr); // fill the local CORBA array with values from lists - std::list::const_iterator + std::list::const_iterator anIt = theErrorsFrom.begin(); int i = 0; @@ -644,7 +645,7 @@ CORBA::Boolean GEOM_IMeasureOperations_i::CheckShape return 0; } - std::list anErrList; + std::list anErrList; bool isOk = GetOperations()->CheckShape(aShape, false, anErrList); ConvertShapeError(anErrList, theErrors); @@ -672,7 +673,7 @@ CORBA::Boolean GEOM_IMeasureOperations_i::CheckShapeWithGeometry return 0; } - std::list anErrList; + std::list anErrList; bool isOk = GetOperations()->CheckShape(aShape, true, anErrList); ConvertShapeError(anErrList, theErrors); @@ -699,7 +700,7 @@ char* GEOM_IMeasureOperations_i::PrintShapeErrors } // Convert the errors sequence - std::list anErrList; + std::list anErrList; ConvertShapeError(theErrors, anErrList); @@ -709,6 +710,66 @@ char* GEOM_IMeasureOperations_i::PrintShapeErrors return CORBA::string_dup(aDescr.ToCString()); } +//============================================================================= +/*! + * ExtractBOPFailure + */ +//============================================================================= +CORBA::Boolean GEOM_IMeasureOperations_i::ExtractBOPFailure + (const GEOM::ListOfGO& theShapes, + CORBA::Boolean theUseTimer, + CORBA::Boolean theTopoOnly, + CORBA::Boolean theRunParallel, + CORBA::Boolean theDoExact, + GEOM::GEOM_Object_out theResultShape, + GEOM::GEOM_IMeasureOperations::ShapeErrors_out theErrors) +{ + GEOM::GEOM_Object_var aNullRes; + theResultShape = aNullRes._retn(); + + // Set the not done flag + theErrors = new GEOM::GEOM_IMeasureOperations::ShapeErrors; + GetOperations()->SetNotDone(); + + // Check for existing shapes + int aNbShapes = theShapes.length(); + if (!aNbShapes) + { + return 0; + } + + // Create the sequence of GEOM objects for the failure shapes + Handle(TColStd_HSequenceOfTransient) aSeqShapes = new TColStd_HSequenceOfTransient; + for (int i = 0; i < aNbShapes; i++) + { + Handle(::GEOM_Object) aShape = GetObjectImpl(theShapes[i]); + if (!aShape.IsNull()) + { + aSeqShapes->Append(aShape); + } + } + + if (!aSeqShapes->Length()) + { + return 0; + } + + // Perform partition operation and check for failures + Handle(::GEOM_Object) aResultShape; + std::list anErrList; + bool isOk = GetOperations()->ExtractBOPFailure + (aSeqShapes, theUseTimer, theTopoOnly, theRunParallel, + theDoExact, aResultShape, anErrList); + + if (!aResultShape.IsNull()) { + theResultShape = GetObject(aResultShape); + } + + ConvertShapeError(anErrList, theErrors); + + return isOk; +} + //============================================================================= /*! * CheckSelfIntersections diff --git a/src/GEOM_I/GEOM_IMeasureOperations_i.hh b/src/GEOM_I/GEOM_IMeasureOperations_i.hh index e1cd715ad..46fad7e1e 100644 --- a/src/GEOM_I/GEOM_IMeasureOperations_i.hh +++ b/src/GEOM_I/GEOM_IMeasureOperations_i.hh @@ -98,6 +98,15 @@ class GEOM_I_EXPORT GEOM_IMeasureOperations_i : ( GEOM::GEOM_Object_ptr theShape, const GEOM::GEOM_IMeasureOperations::ShapeErrors &theErrors); + CORBA::Boolean ExtractBOPFailure + (const GEOM::ListOfGO& theShapes, + CORBA::Boolean theUseTimer, + CORBA::Boolean theTopoOnly, + CORBA::Boolean theRunParallel, + CORBA::Boolean theDoExact, + GEOM::GEOM_Object_out theResultShape, + GEOM::GEOM_IMeasureOperations::ShapeErrors_out theErrors); + CORBA::Boolean CheckSelfIntersections (GEOM::GEOM_Object_ptr theShape, CORBA::Long theCheckLevel, GEOM::ListOfLong_out theIntersections); diff --git a/src/GEOM_SWIG/geomBuilder.py b/src/GEOM_SWIG/geomBuilder.py index e9cf78b47..f5fd61eaf 100644 --- a/src/GEOM_SWIG/geomBuilder.py +++ b/src/GEOM_SWIG/geomBuilder.py @@ -3113,7 +3113,7 @@ class geomBuilder(GEOM._objref_GEOM_Gen): anObj.SetParameters(Parameters) self._autoPublish(anObj, theName, "cylinder") return anObj - + ## Create a portion of cylinder with given base point, axis, radius, height and angle. # @param thePnt Central point of cylinder base. # @param theAxis Cylinder axis. @@ -3196,7 +3196,7 @@ class geomBuilder(GEOM._objref_GEOM_Gen): anObj.SetParameters(Parameters) self._autoPublish(anObj, theName, "cylinder") return anObj - + ## Create a portion of cylinder with given radius, height and angle at # the origin of coordinate system. Axis of the cylinder # will be collinear to the OZ axis of the coordinate system. @@ -3999,7 +3999,7 @@ class geomBuilder(GEOM._objref_GEOM_Gen): # for result publication in the study. Otherwise, if automatic # publication is switched on, default value is used for result name. # - # @return New GEOM.GEOM_Object, containing the created pipe if + # @return New GEOM.GEOM_Object, containing the created pipe if # \a IsGenerateGroups is not set. Otherwise it returns a # list of GEOM.GEOM_Object. Its first element is the created pipe, the # remaining ones are created groups. @@ -4039,7 +4039,7 @@ class geomBuilder(GEOM._objref_GEOM_Gen): publication is switched on, default value is used for result name. Returns: - New GEOM.GEOM_Object, containing the created pipe if + New GEOM.GEOM_Object, containing the created pipe if IsGenerateGroups is not set. Otherwise it returns a list of GEOM.GEOM_Object. Its first element is the created pipe, the remaining ones are created groups. @@ -4076,7 +4076,7 @@ class geomBuilder(GEOM._objref_GEOM_Gen): # for result publication in the study. Otherwise, if automatic # publication is switched on, default value is used for result name. # - # @return New GEOM.GEOM_Object, containing the created pipe if + # @return New GEOM.GEOM_Object, containing the created pipe if # \a IsGenerateGroups is not set. Otherwise it returns new # GEOM.ListOfGO. Its first element is the created pipe, the # remaining ones are created groups. @@ -4112,7 +4112,7 @@ class geomBuilder(GEOM._objref_GEOM_Gen): publication is switched on, default value is used for result name. Returns: - New GEOM.GEOM_Object, containing the created pipe if + New GEOM.GEOM_Object, containing the created pipe if IsGenerateGroups is not set. Otherwise it returns new GEOM.ListOfGO. Its first element is the created pipe, the remaining ones are created groups. @@ -4197,7 +4197,7 @@ class geomBuilder(GEOM._objref_GEOM_Gen): # for result publication in the study. Otherwise, if automatic # publication is switched on, default value is used for result name. # - # @return New GEOM.GEOM_Object, containing the created solids if + # @return New GEOM.GEOM_Object, containing the created solids if # \a IsGenerateGroups is not set. Otherwise it returns new # GEOM.ListOfGO. Its first element is the created solids, the # remaining ones are created groups. @@ -4242,7 +4242,7 @@ class geomBuilder(GEOM._objref_GEOM_Gen): publication is switched on, default value is used for result name. Returns: - New GEOM.GEOM_Object, containing the created solids if + New GEOM.GEOM_Object, containing the created solids if IsGenerateGroups is not set. Otherwise it returns new GEOM.ListOfGO. Its first element is the created solids, the remaining ones are created groups. @@ -4320,7 +4320,7 @@ class geomBuilder(GEOM._objref_GEOM_Gen): # for result publication in the study. Otherwise, if automatic # publication is switched on, default value is used for result name. # - # @return New GEOM.GEOM_Object, containing the created solids if + # @return New GEOM.GEOM_Object, containing the created solids if # \a IsGenerateGroups is not set. Otherwise it returns new # GEOM.ListOfGO. Its first element is the created solids, the # remaining ones are created groups. @@ -4345,7 +4345,7 @@ class geomBuilder(GEOM._objref_GEOM_Gen): publication is switched on, default value is used for result name. Returns: - New GEOM.GEOM_Object, containing the created solids if + New GEOM.GEOM_Object, containing the created solids if IsGenerateGroups is not set. Otherwise it returns new GEOM.ListOfGO. Its first element is the created solids, the remaining ones are created groups. @@ -4378,7 +4378,7 @@ class geomBuilder(GEOM._objref_GEOM_Gen): # for result publication in the study. Otherwise, if automatic # publication is switched on, default value is used for result name. # - # @return New GEOM.GEOM_Object, containing the created pipe if + # @return New GEOM.GEOM_Object, containing the created pipe if # \a IsGenerateGroups is not set. Otherwise it returns new # GEOM.ListOfGO. Its first element is the created pipe, the # remaining ones are created groups. @@ -4408,7 +4408,7 @@ class geomBuilder(GEOM._objref_GEOM_Gen): publication is switched on, default value is used for result name. Returns: - New GEOM.GEOM_Object, containing the created pipe if + New GEOM.GEOM_Object, containing the created pipe if IsGenerateGroups is not set. Otherwise it returns new GEOM.ListOfGO. Its first element is the created pipe, the remaining ones are created groups. @@ -4433,7 +4433,7 @@ class geomBuilder(GEOM._objref_GEOM_Gen): # @param theThickness Thickness of the resulting solid # @param theFacesIDs the list of face IDs to be removed from the # result. It is ignored if \a theShape is a face or a shell. - # It is empty by default. + # It is empty by default. # @param theInside If true the thickness is applied towards inside # @param theName Object name; when specified, this parameter is used # for result publication in the study. Otherwise, if automatic @@ -4456,7 +4456,7 @@ class geomBuilder(GEOM._objref_GEOM_Gen): theThickness Thickness of the resulting solid theFacesIDs the list of face IDs to be removed from the result. It is ignored if theShape is a face or a - shell. It is empty by default. + shell. It is empty by default. theInside If true the thickness is applied towards inside theName Object name; when specified, this parameter is used for result publication in the study. Otherwise, if automatic @@ -4483,7 +4483,7 @@ class geomBuilder(GEOM._objref_GEOM_Gen): # @param theThickness Thickness of the resulting solid # @param theFacesIDs the list of face IDs to be removed from the # result. It is ignored if \a theShape is a face or a shell. - # It is empty by default. + # It is empty by default. # @param theInside If true the thickness is applied towards inside # # @return The modified shape @@ -4503,7 +4503,7 @@ class geomBuilder(GEOM._objref_GEOM_Gen): theThickness Thickness of the resulting solid theFacesIDs the list of face IDs to be removed from the result. It is ignored if \a theShape is a face or - a shell. It is empty by default. + a shell. It is empty by default. theInside If true the thickness is applied towards inside Returns: @@ -4960,7 +4960,7 @@ class geomBuilder(GEOM._objref_GEOM_Gen): RaiseIfFailed("MakeFaceFromSurface", self.ShapesOp) self._autoPublish(anObj, theName, "face") return anObj - + ## Create a non-planar face from a list of closed edges and a list of vertices. # @param theEdges list of Edges(must be closed but not nesessarily belong to the same plane). # @param theVertices list of vertices through which the result face must pass. @@ -4993,7 +4993,7 @@ class geomBuilder(GEOM._objref_GEOM_Gen): RaiseIfFailed("MakeWrappedFace", self.ShapesOp) self._autoPublish(anObj, theName, "face") return anObj - + ## Create a face from a set of edges with the given constraints. # @param theConstraints List of edges and constraint faces (as a sequence of a Edge + Face couples): # - edges should form a closed wire; @@ -5002,9 +5002,9 @@ class geomBuilder(GEOM._objref_GEOM_Gen): # @param theName Object name; when specified, this parameter is used # for result publication in the study. Otherwise, if automatic # publication is switched on, default value is used for result name. - # + # # @return New GEOM.GEOM_Object, containing the created face. - # + # # @ref tui_creation_face "Example" @ManageTransactions("ShapesOp") def MakeFaceWithConstraints(self, theConstraints, theName=None): @@ -5123,7 +5123,7 @@ class geomBuilder(GEOM._objref_GEOM_Gen): RaiseIfFailed("MakeCompound", self.ShapesOp) self._autoPublish(anObj, theName, "compound") return anObj - + ## Create a solid (or solids) from the set of faces and/or shells. # @param theFacesOrShells List of faces and/or shells. # @param isIntersect If TRUE, forces performing intersections @@ -11982,6 +11982,56 @@ class geomBuilder(GEOM._objref_GEOM_Gen): """ return self.MeasuOp.CheckBOPArguments(theShape) + + ## Performs general fuse BOP on the given list of shapes + # and extracts CheckShape information from its invalid result. + # @param theShapes List of shapes for the BOP. + # @param theTimer If True, the execution time of the operation is measured. + # @param theTopo If True, only the topological entities will be checked. + # @param theParallel If True, the operation will be executed in parallel. + # @param theExact If True, an exact check will be performed. + # @param theVerbose If True, prints execution errors and resulting shape errors. + # @param theName Object name; when specified, this parameter is used + # for result publication in the study. Otherwise, if automatic + # publication is switched on, default value is used for result name. + # @return (isValid, shapeResult, listOfErrors), where + # isValid - a boolean value (whether result shape is valid or not), + # shapeResult - the result shape itself as GEOM::Object, + # listOfErrors - the list of GEOM.GEOM_IMeasureOperations.ShapeError. + def ExtractBOPFailure(self, theShapes, theTimer=False, theTopo=False, theParallel=False, theExact=False, theVerbose=False, theName=None): + """ + Performs general fuse BOP on the given list of shapes + and extracts CheckShape information from its invalid result. + + Parameters: + theShapes List of shapes for the BOP. + theTimer If True, the time of the operation is measured. + theTopo If True, only the topological entities will be checked. + theParallel If True, the operation will be executed in parallel. + theExact If True, an exact check will be performed. + theVerbose If True, prints execution errors and resulting shape errors. + theName Object name; when specified, this parameter is used + for result publication in the study. Otherwise, if automatic + publication is switched on, default value is used for result name. + + Returns: + (isValid, shapeResult, listOfErrors), where + isValid - a boolean value (whether result shape is valid or not), + shapeResult - the result shape itself as GEOM::Object, + listOfErrors - the list of GEOM.GEOM_IMeasureOperations.ShapeError. + """ + (IsValid, ShapeRes, ShapeErrors) = self.MeasuOp.ExtractBOPFailure(theShapes, theTimer, theTopo, theParallel, theExact) + if theVerbose: + if not self.MeasuOp.IsDone(): + print("== ExtractBOPFailure execution trace:") + print(self.MeasuOp.GetErrorCode()) + if not IsValid: + print("== ExtractBOPFailure result errors:") + self.PrintShapeErrors(ShapeRes, ShapeErrors) + if ShapeRes: + self._autoPublish(ShapeRes, theName, "InvalidBOPResult") + return (IsValid, ShapeRes, ShapeErrors) + ## Detect intersections of the given shapes with algorithm based on mesh intersections. # @param theShape1 First source object # @param theShape2 Second source object diff --git a/src/IGESPlugin/CMakeLists.txt b/src/IGESPlugin/CMakeLists.txt index eb9cdb048..16f24d72f 100644 --- a/src/IGESPlugin/CMakeLists.txt +++ b/src/IGESPlugin/CMakeLists.txt @@ -26,6 +26,7 @@ ENDIF() # additional include directories INCLUDE_DIRECTORIES( ${OpenCASCADE_INCLUDE_DIR} + ${CommonGeomLib_INCLUDE_DIRS} ${KERNEL_INCLUDE_DIRS} ${PROJECT_BINARY_DIR}/idl ${PROJECT_SOURCE_DIR}/src/GEOMAlgo diff --git a/src/STEPPlugin/CMakeLists.txt b/src/STEPPlugin/CMakeLists.txt index d00029a35..b30d761a3 100644 --- a/src/STEPPlugin/CMakeLists.txt +++ b/src/STEPPlugin/CMakeLists.txt @@ -26,6 +26,7 @@ ENDIF() # additional include directories INCLUDE_DIRECTORIES( ${OpenCASCADE_INCLUDE_DIR} + ${CommonGeomLib_INCLUDE_DIRS} ${KERNEL_INCLUDE_DIRS} ${PROJECT_BINARY_DIR}/idl ${PROJECT_SOURCE_DIR}/src/GEOMAlgo diff --git a/src/STLPlugin/CMakeLists.txt b/src/STLPlugin/CMakeLists.txt index 153ee83ad..63d08d0b9 100644 --- a/src/STLPlugin/CMakeLists.txt +++ b/src/STLPlugin/CMakeLists.txt @@ -26,6 +26,7 @@ ENDIF() # additional include directories INCLUDE_DIRECTORIES( ${OpenCASCADE_INCLUDE_DIR} + ${CommonGeomLib_INCLUDE_DIRS} ${KERNEL_INCLUDE_DIRS} ${PROJECT_BINARY_DIR}/idl ${PROJECT_SOURCE_DIR}/src/GEOMAlgo diff --git a/src/VTKPlugin/CMakeLists.txt b/src/VTKPlugin/CMakeLists.txt index baeaf1342..7437a355b 100644 --- a/src/VTKPlugin/CMakeLists.txt +++ b/src/VTKPlugin/CMakeLists.txt @@ -26,6 +26,7 @@ ENDIF() # additional include directories INCLUDE_DIRECTORIES( ${OpenCASCADE_INCLUDE_DIR} + ${CommonGeomLib_INCLUDE_DIRS} ${KERNEL_INCLUDE_DIRS} ${PROJECT_BINARY_DIR}/idl ${PROJECT_SOURCE_DIR}/src/GEOMAlgo diff --git a/src/XAOPlugin/CMakeLists.txt b/src/XAOPlugin/CMakeLists.txt index 843637406..62571cb00 100644 --- a/src/XAOPlugin/CMakeLists.txt +++ b/src/XAOPlugin/CMakeLists.txt @@ -26,6 +26,7 @@ ENDIF() # additional include directories INCLUDE_DIRECTORIES( ${OpenCASCADE_INCLUDE_DIR} + ${CommonGeomLib_INCLUDE_DIRS} ${KERNEL_INCLUDE_DIRS} ${PROJECT_BINARY_DIR}/idl ${PROJECT_SOURCE_DIR}/src/GEOMAlgo diff --git a/test/data/ExtractBOPFailure_compound1.brep b/test/data/ExtractBOPFailure_compound1.brep new file mode 100644 index 000000000..178733db0 --- /dev/null +++ b/test/data/ExtractBOPFailure_compound1.brep @@ -0,0 +1,388 @@ +DBRep_DrawableShape + +CASCADE Topology V3, (c) Open Cascade +Locations 2 +1 + 1 0 0 -7.567891 + 0 1 0 -4.341567 + 0 0 1 -6.123456 +2 1 -1 0 +Curve2ds 20 +1 5.2296342291324773 3.3322056701893321 -0.019393351731739859 -0.99981193126938084 +1 4.1177697329478473 -7.9576022773085979 0.74914523473738692 0.66240577991912586 +2 7.6778616423679917 5.5784416873630649 1.0327963672288199e-28 1 -1 1.0327963672288199e-28 13.996383126259545 +1 1.2238101114815878 -6.1633524984935972 -0.18530824692372716 -0.98268044328868942 +1 1.2235485004159372 -2.2110670843958085 6.6192351428950508e-05 -0.99999999780928628 +1 -0.76442260860377154 0.24528750719338177 0.62910141048581703 -0.77732323735030318 +1 -3.7293599477436921 -2.8998812708177271 0.68595070867481067 0.72764800918337236 +2 8.2082756373678425 6.9866174666722882 1 -5.2064482382916161e-32 5.2064482382916161e-32 1 15.500000020945576 +1 -5.5702632964129428 -0.1128096580751663 0.62013158110931121 0.78449781523651529 +1 -1.2787866923231981 5.3161253012195147 0.66335395303032052 -0.74830577506728313 +1 6.2831853071795862 -27.994292694933499 -1 0 +1 2.2305029134341128 -29.744292694933499 0 1 +1 1.1682335865018412e-13 -26.364292694933447 1 0 +1 2.2737127428085482 -25.744292694933499 0 -1 +1 1.1577157318429796e-13 -25.744292694933449 1 0 +1 2.2305029134341128 -25.744292694933399 0 1 +1 6.2831853071795862 -24.494292694933499 -1 0 +7 0 0 5 6 2 2.66538798008808 -22.744292694933499 2.6653879800880054 -23.468292694933499 2.6653879800879281 -24.192292694933485 2.6653879800878677 -24.916292694933531 2.6653879800877802 -25.6402926949335 2.6653879800877056 -26.3642926949335 + 0 6 3.6200000000000001 6 +1 -1.5707963267948966 -26.364292694933503 1 0 +1 2.6969123268332003 -29.744292694933499 0 1 +Curves 20 +1 3.6643099095142699 2.9989666286603298 7.3799999999999901 0.99981193126938084 0.019393351731739859 0 +1 14.9541178570122 4.1108311248449603 7.3799999999999901 -0.66240577991912586 -0.74914523473738692 0 +2 1.4180738923405372 0.55073921542481585 7.3800000000004342 -2.974710134687989e-14 -1.1637659715336122e-14 -1 -1 0 2.974710134687989e-14 -3.46186642992605e-28 1 -1.1637659715336122e-14 13.996383126259545 +1 13.159868078197199 7.0047907463112198 7.3799999999999901 0.98268044328868942 0.18530824692372716 0 +1 9.2075826640994105 7.0050523573768704 7.3799999999999901 0.99999999780928628 -6.6192351428950508e-05 0 +1 6.7512280725102203 8.9930234663965791 7.3799999999999901 0.77732323735030318 -0.62910141048581703 0 +1 9.8963968505213291 11.9579608055365 7.3799999999999599 -0.72764800918337236 -0.68595070867481067 6.9864494891450316e-15 +2 0.0098981130313138266 0.020325220424965096 7.3800000000000123 -4.8764518640683504e-16 -3.985833116056589e-15 -1 0 -1 3.985833116056589e-15 -1 1.9436723328659514e-30 4.8764518640683504e-16 15.500000020945576 +1 7.1093252377787683 13.79886415420575 7.3799999999999537 -0.78449781523651529 -0.62013158110931121 2.951923868206801e-15 +1 1.6803902784840878 9.5073875501160057 7.3799999999999741 0.74830577506728313 -0.66335395303032052 1.65532199479636e-15 +2 0.048629684365062174 0.040085253947511945 5.75 -1.8938307431288352e-32 -1.4228181456116284e-32 1 -1 0 -1.8938307431288352e-32 2.6945767460408616e-64 -1 -1.4228181456116284e-32 15.447113622753015 +1 9.5159344006809405 12.245963374044599 4 0 0 1 +2 0.048629684364520642 0.040085253947925281 7.3800000000000505 -1.1682335865018412e-13 9.4687192060776203e-14 -1 -1 0 1.1682335865018412e-13 1.1061675797694924e-26 1 9.4687192060776203e-14 15.447113622753017 +1 10.0343474285764 11.8256170793334 8 0 0 -1 +2 0.048629684364520642 0.040085253947925281 8.0000000000000497 -1.1577157318429796e-13 9.3871390575314678e-14 -1 -1 0 1.1577157318429796e-13 1.0867638563901861e-26 1 9.3871390575314678e-14 15.447113622753017 +1 9.5159344006809405 12.245963374044599 8.0000000000000995 0 0 1 +2 0.048629684365062174 0.040085253947511945 9.25 -1.8938307431288352e-32 -1.4228181456116284e-32 1 -1 0 -1.8938307431288352e-32 2.6945767460408616e-64 -1 -1.4228181456116284e-32 15.447113622753015 +1 13.7771149464134 7.1211876881706102 11 -7.183940367077256e-13 1.4252564751486263e-12 -1 +2 0.048629684365860015 0.040085253945864707 7.3799999999999955 -8.9410861073054036e-15 1.7961675054224776e-14 -1 0 -1 -1.7961675054224776e-14 -1 -1.6059688329126317e-28 8.9410861073054036e-15 15.447113622753015 +1 13.9934840908598 6.6849595835271503 4 0 0 1 +Polygon3D 0 +PolygonOnTriangulations 0 +Surfaces 2 +1 6.9965155797036021 8.2286008577928076 7.3799999999999759 1.0131042642695293e-16 -3.4719227099992637e-15 -1 0 -1 3.4719227099992637e-15 -1 -3.5174197027144744e-31 -1.0131042642695293e-16 +2 0.048629684365062174 0.040085253947511945 33.744292694933499 -1.8938307431288352e-32 -1.4228181456116284e-32 1 -1 0 -1.8938307431288352e-32 -2.6945767460408616e-64 1 1.4228181456116284e-32 15.447113622753015 +Triangulations 0 + +TShapes 45 +Ve +0.00100000000000355 +1.33968696229361 -1.24089670248843 1.25654399999999 +0 0 + +0101101 +* +Ve +0.001 +6.582955015073 -1.13919303363718 1.25654399999999 +0 0 + +0101101 +* +Ed + 0.001 1 1 0 +1 1 0 5.2442543330348 10.4885086660696 +2 1 1 0 5.2442543330348 10.4885086660696 +0 + +0101000 ++45 2 -44 2 * +Ve +0.001 +7.3862268570122 -0.23073587515504 1.25654399999999 +0 0 + +0101101 +* +Ed + 0.001 1 1 0 +1 2 0 0 1.21265826218677 +2 2 1 0 0 1.21265826218677 +0 + +0101000 ++42 2 -44 2 * +Ve +0.001 +6.2085640030866 2.77949617536757 1.25654399999999 +0 0 + +0101101 +* +Ed + 0.001 1 1 0 +1 3 0 2.65294738721352 2.88440884989702 +2 3 1 0 2.65294738721352 2.88440884989702 +0 + +0101000 ++40 2 -42 2 * +Ve +0.001 +5.5919770781972 2.66322374631122 1.25654399999999 +0 0 + +0101101 +* +Ed + 0.001 1 1 0 +1 4 0 0 0.627454152670321 +2 4 1 0 0 0.627454152670321 +0 + +0101000 ++38 2 -40 2 * +Ve +0.001 +1.63969166409941 2.66348535737687 1.25654399999999 +0 0 + +0101101 +* +Ed + 0.001 1 1 0 +1 5 0 0 3.95228542275611 +2 5 1 0 0 3.95228542275611 +0 + +0101000 ++36 2 -38 2 * +Ve +0.001 +-0.81666292748978 4.65145646639658 1.25654399999999 +0 0 + +0101101 +* +Ed + 0.001 1 1 0 +1 6 0 0 3.16001693190374 +2 6 1 0 0 3.16001693190374 +0 + +0101000 ++34 2 -36 2 * +Ve +0.001 +2.32850585052133 7.6163938055365 1.25654399999996 +0 0 + +0101101 +* +Ed + 0.001 1 1 0 +1 7 0 0 4.32237666882492 +2 7 1 0 0 4.32237666882492 +0 + +0101000 ++32 2 -34 2 * +Ve +0.00100000000000266 +-0.45856576222123 9.4572971542058 1.25654399999995 +0 0 + +0101101 +* +Ed + 0.001 1 1 0 +1 8 0 3.61736770330259 3.83328128895929 +2 8 1 0 3.61736770330259 3.83328128895929 +0 + +0101000 ++30 2 -32 2 * +Ve +0.00100000000000355 +-5.88750072151591 5.16582055011601 1.25654399999997 +0 0 + +0101101 +* +Ed + 0.00100000000000266 1 1 0 +1 9 0 0 6.92026778641561 +2 9 1 0 0 6.92026778641561 +0 + +0101000 ++30 2 -28 2 * +Ed + 0.00100000000000355 1 1 0 +1 10 0 0 9.65806749675251 +2 10 1 0 0 9.65806749675251 +0 + +0101000 ++28 2 -45 2 * +Wi + +0101100 +-43 0 +41 0 +39 0 +37 0 +35 0 +33 0 +31 0 +29 0 -27 0 -26 0 +* +Fa +0 0.001 1 0 + +0111000 ++25 0 * +Ve +0.001100100001 +6.4255930908598 2.34339258352715 -0.373456 +0 0 + +0101101 +* +Ve +0.001100100001 +1.94804340068094 7.9043963740446 -0.373456 +0 0 + +0101101 +* +Ed + 0.0011 1 1 0 +1 11 0 3.58627298034639 4.05268239374548 +2 11 2 0 3.58627298034639 4.05268239374548 +0 + +0101000 ++23 2 -22 2 * +Ve +0.0011 +1.94804340068094 7.9043963740446 1.2565440000001 +0 0 + +0101101 +* +Ed + 0.0011 1 1 0 +1 12 0 1.75 3.3800000000001 +2 12 2 0 1.75 3.3800000000001 +0 + +0101000 ++22 2 -20 2 * +Ve +0.0011 +2.4664564285764 7.4840500793334 1.256544 +0 0 + +0101101 +* +Ed + 0.0011 1 1 0 +1 13 0 2.23050291343416 2.27371274280859 +2 13 2 0 2.23050291343416 2.27371274280859 +0 + +0101000 ++20 2 -18 2 * +Ve +0.0011 +2.4664564285764 7.4840500793334 1.876544 +0 0 + +0101101 +* +Ed + 0.0011 1 1 0 +1 14 0 0 0.62 +2 14 2 0 0 0.62 +0 + +0101000 ++16 2 -18 2 * +Ve +0.0011 +1.94804340068094 7.9043963740446 1.8765440000001 +0 0 + +0101101 +* +Ed + 0.0011 1 1 0 +1 15 0 2.23050291343416 2.27371274280859 +2 15 2 0 2.23050291343416 2.27371274280859 +0 + +0101000 ++14 2 -16 2 * +Ve +0.001100100001 +1.94804340068094 7.9043963740446 3.126544 +0 0 + +0101101 +* +Ed + 0.0011 1 1 0 +1 16 0 0 1.2499999999999 +2 16 2 0 0 1.2499999999999 +0 + +0101000 ++14 2 -12 2 * +Ve +0.001100100001 +6.2092239464121 2.7796206881731 3.126544 +0 0 + +0101101 +* +Ed + 0.0011 1 1 0 +1 17 0 3.61779732709169 4.05268239374548 +2 17 2 0 3.61779732709169 4.05268239374548 +0 + +0101000 ++10 2 -12 2 * +Ve +0.0011 +6.2092239464108 2.77962068817577 1.256544 +0 0 + +0101101 +* +Ed + 0.0011 1 1 0 +1 18 0 1.75 3.62 +2 18 2 0 1.75 3.62 +0 + +0101000 ++10 2 -8 2 * +Ve +0.0011 +6.4255930908598 2.34339258352715 1.25654399999999 +0 0 + +0101101 +* +Ed + 0.0011 1 1 0 +1 19 0 4.23618430688248 4.26770865362798 +2 19 2 0 4.23618430688248 4.26770865362798 +0 + +0101000 ++8 2 -6 2 * +Ed + 0.0011 1 1 0 +1 20 0 1.75 3.37999999999999 +2 20 2 0 1.75 3.37999999999999 +0 + +0101000 ++23 2 -6 2 * +Wi + +0101100 +-21 0 -19 0 -17 0 +15 0 +13 0 -11 0 +9 0 -7 0 -5 0 +4 0 +* +Fa +0 0.0011 2 0 + +0111000 ++3 0 * +Co + +1100000 ++24 0 -2 0 * + ++1 1 +0 + diff --git a/test/test_ExtractBOPFailure.py b/test/test_ExtractBOPFailure.py new file mode 100755 index 000000000..c3dd04c4f --- /dev/null +++ b/test/test_ExtractBOPFailure.py @@ -0,0 +1,85 @@ +# Copyright (C) 2024 CEA, EDF +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +# Test ExtractBOPFailure method + +from inspect import getfile +from os.path import abspath, dirname, join +import salome +from salome.geom import geomBuilder +geompy = geomBuilder.New() + +data_dir = abspath(join(dirname(getfile(lambda: None)), 'data')) + +### Case 1: Invalid face with (3) intersecting wires +Shapes_1 = geompy.ImportBREP(join(data_dir, "ExtractBOPFailure_compound1.brep")) +geompy.addToStudy( Shapes_1, 'CompoundPostIdealisation' ) + +try : + Partition_1 = geompy.MakePartition([Shapes_1],[]) +except : + print("EXCEPTION: Partition problem") + +print("Case 1: Invalid face with (3) intersecting wires") +(IsValid, GFRes, ShapeErrors) = geompy.ExtractBOPFailure([Shapes_1], theTimer=True, theVerbose=True) + +assert GFRes is not None, "Resulting shape expected in Case #1" +geompy.addToStudy( GFRes, 'GFRes_Case_1' ) +assert not IsValid, "IsValid == False expected in Case #1" + +assert len(ShapeErrors) == 1, "One error expected" +list_ids = ShapeErrors[0].incriminated +assert len(list_ids) == 1, "One incriminated shape expected" + +[Face_1] = geompy.SubShapes(GFRes, list_ids) +geompy.addToStudyInFather( GFRes, Face_1, 'Bad face' ) + +list_wires = geompy.ExtractShapes(Face_1, geompy.ShapeType["WIRE"], True, "Wire") + +assert len(list_wires) == 3, "Three wires expected" + +### Case 2: Empty list of input shapes +print("Case 2: Empty list of input shapes") +(IsValid, GFRes, ShapeErrors) = geompy.ExtractBOPFailure([], theVerbose=True) +assert GFRes is None, "General Fuse result is NOT expected on empty list of shapes" +assert not IsValid, "IsValid == False expected on empty list of shapes" +assert len(ShapeErrors) == 0, "ExtractBOPFailure should report no errors on empty list of shapes" + +### Case 3: One shape in list, and it is not a COMPOUND +print("Case 3: One shape in list, and it is not a COMPOUND") +(IsValid, GFRes, ShapeErrors) = geompy.ExtractBOPFailure([geompy.MakeBoxDXDYDZ(10,10,10)], theVerbose=True) +assert GFRes is None, "General Fuse result is NOT expected" +assert not IsValid, "IsValid == False expected" +assert len(ShapeErrors) == 0, "ExtractBOPFailure should report no errors here" + +### Case 4: Unusual type Case (two orthogonal faces, Partition OK) +print("Case 4: Unusual type Case (two orthogonal faces, Partition OK)") +origin = geompy.MakeVertex(0,0,0) +oX = geompy.MakeVectorDXDYDZ(1,0,0) +YOZ = geompy.MakePlane(origin, oX, 5) +oY = geompy.MakeVectorDXDYDZ(0,1,0) +XOZ = geompy.MakePlane(origin, oY, 5) +(IsValid, GFRes, ShapeErrors) = geompy.ExtractBOPFailure([YOZ, XOZ], theVerbose=True) +assert GFRes is not None, "General Fuse result is expected" +geompy.addToStudy( GFRes, 'GFRes_Case_4' ) +assert IsValid, "Valid result is expected" +assert len(ShapeErrors) == 0, "ExtractBOPFailure should report no errors here" + +if salome.sg.hasDesktop(): + salome.sg.updateObjBrowser() diff --git a/test/tests.set b/test/tests.set index 6465dfcb5..fd6a43e8d 100644 --- a/test/tests.set +++ b/test/tests.set @@ -21,7 +21,8 @@ SET(ALL_TESTS test_perf_01.py test_patch_face_01.py test_set_autocolor.py - ) + test_ExtractBOPFailure.py +) IF(${OpenCASCADE_VERSION}.${OpenCASCADE_SP_VERSION} VERSION_GREATER "7.5.3.3") LIST(APPEND ALL_TESTS