From: skv Date: Thu, 22 Jan 2015 09:14:55 +0000 (+0300) Subject: 0022775: [CEA 1091] Add an option on GetNonBlocks to retrieve quadrangular faces... X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=8bfdc37bff468c18f58126f74488be97d60a2288;p=modules%2Fgeom.git 0022775: [CEA 1091] Add an option on GetNonBlocks to retrieve quadrangular faces defined on C1 edges --- diff --git a/doc/salome/gui/GEOM/images/measures2.png b/doc/salome/gui/GEOM/images/measures2.png index 21e5218a4..a9e064b5e 100644 Binary files a/doc/salome/gui/GEOM/images/measures2.png and b/doc/salome/gui/GEOM/images/measures2.png differ diff --git a/doc/salome/gui/GEOM/images/measures2a.png b/doc/salome/gui/GEOM/images/measures2a.png index 3068f49b1..718c60f90 100644 Binary files a/doc/salome/gui/GEOM/images/measures2a.png and b/doc/salome/gui/GEOM/images/measures2a.png differ diff --git a/doc/salome/gui/GEOM/input/get_non_blocks.doc b/doc/salome/gui/GEOM/input/get_non_blocks.doc index 79f6ba021..e1b687eff 100644 --- a/doc/salome/gui/GEOM/input/get_non_blocks.doc +++ b/doc/salome/gui/GEOM/input/get_non_blocks.doc @@ -5,24 +5,45 @@ This operation retrieves all non-block solids and non-quadrangular faces from the selected shape. -A non-block solid is a solid that does not have 6 faces, or has 6 faces, but some of them are not quadrangular. +A block solid is a solid that has 6 faces and 12 edges. + +A quadrangular face is a face that has 1 wire with 4 edges. If there are +more than 4 edges in a single wire and C1 continuity mode is switched on, +a face is quadrangular if it has 4 bounds of C1 continuity. + +All solids and faces from a shape that do not satisfy these conditions are +returned by this operation. \image html measures2.png -\b Preview option shows non block solids and faces in the viewer. +It is possible to select an \b Object to be explored, to check or uncheck +Use C1 criterion option and to set the Angular Tolerance +to check C1 continuity between neighbor edges in a wire. -Press \b Apply or Apply and Close button to publish non block solids and faces in the Object -Browser under the processed object. Solids and faces are published separately in two groups. +\b Preview option shows non-block solids and non-quadrangular faces in the viewer. + +Press \b Apply or Apply and Close button to publish non-block solids +and non-quadrangular faces in the Object Browser under the processed object. +Solids and faces are published separately in two groups. If no bad sub-shapes have been found, the corresponding warning is shown. \image html measures2a.png \n TUI Command: -geompy.GetNonBlocks(Compound). Returns a tuple of two GEOM_Objects. - -The first object is a group of all non block solids; the second object is a group of all non -quadrangular faces. +geompy.GetNonBlocks(theShape, theIsUseC1 = False, theAngTolerance = 1.e-12). \n +where \n +\em theShape is the shape to explore, \n +\em theIsUseC1 is the flag to check if there are 4 bounds on a face + taking into account C1 continuity, \n +\em theAngTolerance the angular tolerance to check if two neighbor edges are + codirectional in the common vertex with this tolerance. This parameter is + used only if \em theIsUseC1 is set to True. + +This command returns a tuple of two GEOM_Objects. + +The first object is a group of all non-block solids; the second object is a group +of all non-quadrangular faces. See also a \ref tui_get_non_blocks_page "TUI example". diff --git a/idl/GEOM_Gen.idl b/idl/GEOM_Gen.idl index 8863bae26..890d9b52b 100644 --- a/idl/GEOM_Gen.idl +++ b/idl/GEOM_Gen.idl @@ -2781,12 +2781,17 @@ module GEOM * \brief Retrieve all non blocks solids and faces from a shape. * * \param theShape The shape to explore. + * \param theToleranceC1 the tolerance to check if two neighbor edges are + * collinear in the common vertex with this tolerance. Negative + * value means that C1 criterion is not used (old implementation). * \param theNonQuads Output parameter. Group of all non quadrangular faces. * * \return Group of all non block solids (= not 6 faces, or with 6 * faces, but with the presence of non-quadrangular faces). */ - GEOM_Object GetNonBlocks (in GEOM_Object theShape, out GEOM_Object theNonQuads); + GEOM_Object GetNonBlocks (in GEOM_Object theShape, + in double theToleranceC1, + out GEOM_Object theNonQuads); /*! * \brief Remove all seam and degenerated edges from \a theShape. diff --git a/src/GEOMGUI/GEOM_msg_en.ts b/src/GEOMGUI/GEOM_msg_en.ts index 06cb15a74..22961d63e 100644 --- a/src/GEOMGUI/GEOM_msg_en.ts +++ b/src/GEOMGUI/GEOM_msg_en.ts @@ -407,6 +407,10 @@ Please, select face, shell or solid and try again GEOM_NONBLOCKS NonBlocksGroup + + GEOM_USE_C1_CRITERION + Use C1 criterion + GEOM_CHECK_INFOS Object And Its Topological Information diff --git a/src/GEOMImpl/GEOMImpl_IBlocksOperations.cxx b/src/GEOMImpl/GEOMImpl_IBlocksOperations.cxx index cca9f381f..8eb8f09da 100644 --- a/src/GEOMImpl/GEOMImpl_IBlocksOperations.cxx +++ b/src/GEOMImpl/GEOMImpl_IBlocksOperations.cxx @@ -88,6 +88,7 @@ #include #include +#include #include #include @@ -103,6 +104,147 @@ #include #include // CAREFUL ! position of this file is critic : see Lucien PIGNOLONI / OCC + +/** + * This function returns Standard_True if the face is quadrangular. It means + * that it has only 1 wire with 4 edges. If there are more then 4 edges in + * the wire and theToleranceC1 is not negative the new implementation is used. + * According to it the face is quadrangular if it is quadrangular according to + * an old implementation or if it has a single wire with more then 4 edges + * that form exactly 4 bounds of C1 continuity with the given tolerance. + * + * \param theFace the face to be checked + * \param theToleranceC1 if negative, it is not used; otherwise it is used + * to check if two neighbor edges of face have C1 continuity. + * \return Standard_True if the face is quadrangular; Standard_False otherwise. + */ +static Standard_Boolean IsQuadrangle(const TopoDS_Face &theFace, + const Standard_Real theToleranceC1) +{ + TopExp_Explorer aFExp (theFace, TopAbs_WIRE); + + if (!aFExp.More()) { + // no wire in the face + return Standard_False; + } + + TopoDS_Shape aWire = aFExp.Current(); + + aFExp.Next(); + + if (aFExp.More()) { + // multiple wires in the face + return Standard_False; + } + + // Check number of edges in the face + Standard_Integer aNbEdges = 0; + TopTools_MapOfShape aMapEdges; + TopExp_Explorer aWExp(aWire, TopAbs_EDGE); + + for (; aWExp.More(); aWExp.Next()) { + if (aMapEdges.Add(aWExp.Current())) { + aNbEdges++; + + if (aNbEdges > 4) { + break; + } + } + } + + if (aNbEdges < 4) { + return Standard_False; + } + + if (aNbEdges > 4) { + if (theToleranceC1 < 0.) { + return Standard_False; + } + + // Check if a wire has 4 bounds of C1 continuity. + BRepTools_WireExplorer aWireExp(TopoDS::Wire(aWire), theFace); + TopTools_ListOfShape anEdges; + + for (aNbEdges = 0; aWireExp.More(); aWireExp.Next()) { + const TopoDS_Edge &anEdge = aWireExp.Current(); + + // Skip degenerated edges. + if (!BRep_Tool::Degenerated(anEdge)) { + anEdges.Append(anEdge); + ++aNbEdges; + } + } + + if (aNbEdges < 4) { + return Standard_False; + } + + // Compute number of sharp corners. + anEdges.Append(anEdges.First()); // To make a loop. + + TopTools_ListIteratorOfListOfShape anIter(anEdges); + Standard_Real aPar[2]; + Standard_Integer aNbCorners = 0; + TopoDS_Edge anEdge1 = TopoDS::Edge(anEdges.First()); + Handle(Geom_Curve) aCurve1 = BRep_Tool::Curve(anEdge1, aPar[0], aPar[1]); + Handle(Geom_Curve) aCurve2; + TopoDS_Edge anEdge2; + TopoDS_Vertex aCommonVtx; + gp_Pnt aPnt; + gp_Vec aVec1; + gp_Vec aVec2; + Standard_Boolean isReversed1 = (anEdge1.Orientation() == TopAbs_REVERSED); + Standard_Boolean isReversed2; + + for (anIter.Next(); anIter.More(); anIter.Next()) { + TopoDS_Edge anEdge2 = TopoDS::Edge(anIter.Value()); + + if (!TopExp::CommonVertex(anEdge1, anEdge2, aCommonVtx)) { + // NEVERREACHED + return Standard_False; + } + + // Check the angle between tangent vectors of 2 curves at this point. + Standard_Real aParam1 = BRep_Tool::Parameter(aCommonVtx, anEdge1); + Standard_Real aParam2 = BRep_Tool::Parameter(aCommonVtx, anEdge2); + + aCurve2 = BRep_Tool::Curve(anEdge2, aPar[0], aPar[1]); + isReversed2 = (anEdge2.Orientation() == TopAbs_REVERSED); + aCurve1->D1(aParam1, aPnt, aVec1); + aCurve2->D1(aParam2, aPnt, aVec2); + + if (isReversed1) { + aVec1.Reverse(); + } + + if (isReversed2) { + aVec2.Reverse(); + } + const Standard_Real anAngle = aVec1.Angle(aVec2); + + if (anAngle > theToleranceC1) { + ++aNbCorners; + + if (aNbCorners > 4) { + break; + } + } + + // Go to the next couple of edges. + anEdge1 = anEdge2; + aCurve1 = aCurve2; + isReversed1 = isReversed2; + } + + // Check the total number of corners. + if (aNbCorners != 4) { + return Standard_False; + } + } + + return Standard_True; +} + //============================================================================= /*! * constructor: @@ -1647,7 +1789,8 @@ void GEOMImpl_IBlocksOperations::AddBlocksFrom (const TopoDS_Shape& theShape, TopTools_ListOfShape& BLO, TopTools_ListOfShape& NOT, TopTools_ListOfShape& EXT, - TopTools_ListOfShape& NOQ) + TopTools_ListOfShape& NOQ, + const Standard_Real theToleranceC1) { TopAbs_ShapeEnum aType = theShape.ShapeType(); switch (aType) { @@ -1656,7 +1799,7 @@ void GEOMImpl_IBlocksOperations::AddBlocksFrom (const TopoDS_Shape& theShape, { TopoDS_Iterator It (theShape); for (; It.More(); It.Next()) { - AddBlocksFrom(It.Value(), BLO, NOT, EXT, NOQ); + AddBlocksFrom(It.Value(), BLO, NOT, EXT, NOQ, theToleranceC1); } } break; @@ -1676,41 +1819,12 @@ void GEOMImpl_IBlocksOperations::AddBlocksFrom (const TopoDS_Shape& theShape, TopExp_Explorer expF (theShape, TopAbs_FACE); for (; expF.More(); expF.Next()) { - if (mapFaces.Add(expF.Current())) { - nbFaces++; - //0021483//if (nbFaces > 6) break; + TopoDS_Face aF = TopoDS::Face(expF.Current()); - // get wire - TopoDS_Shape aF = expF.Current(); - TopExp_Explorer wires (aF, TopAbs_WIRE); - if (!wires.More()) { - // no wire in the face - hasNonQuadr = Standard_True; - NOQ.Append(aF);//0021483 - //0021483//break; - continue; - } - TopoDS_Shape aWire = wires.Current(); - wires.Next(); - if (wires.More()) { - // multiple wires in the face - hasNonQuadr = Standard_True; - NOQ.Append(aF);//0021483 - //0021483//break; - continue; - } + if (mapFaces.Add(aF)) { + nbFaces++; - // Check number of edges in the face - Standard_Integer nbEdges = 0; - TopTools_MapOfShape mapEdges; - TopExp_Explorer expW (aWire, TopAbs_EDGE); - for (; expW.More(); expW.Next()) { - if (mapEdges.Add(expW.Current())) { - nbEdges++; - if (nbEdges > 4) break; - } - } - if (nbEdges != 4) { + if (!IsQuadrangle(aF, theToleranceC1)) { hasNonQuadr = Standard_True; NOQ.Append(aF);//0021483 } @@ -1732,34 +1846,10 @@ void GEOMImpl_IBlocksOperations::AddBlocksFrom (const TopoDS_Shape& theShape, TopTools_MapOfShape mapFaces; TopExp_Explorer expF (theShape, TopAbs_FACE); for (; expF.More(); expF.Next()) { - if (mapFaces.Add(expF.Current())) { - // get wire - TopoDS_Shape aF = expF.Current(); - TopExp_Explorer wires (aF, TopAbs_WIRE); - if (!wires.More()) { - // no wire in the face - NOQ.Append(aF);//0021483 - continue; - } - TopoDS_Shape aWire = wires.Current(); - wires.Next(); - if (wires.More()) { - // multiple wires in the face - NOQ.Append(aF);//0021483 - continue; - } + TopoDS_Face aF = TopoDS::Face(expF.Current()); - // Check number of edges in the face - Standard_Integer nbEdges = 0; - TopTools_MapOfShape mapEdges; - TopExp_Explorer expW (aWire, TopAbs_EDGE); - for (; expW.More(); expW.Next()) { - if (mapEdges.Add(expW.Current())) { - nbEdges++; - if (nbEdges > 4) break; - } - } - if (nbEdges != 4) { + if (mapFaces.Add(aF)) { + if (!IsQuadrangle(aF, theToleranceC1)) { NOQ.Append(aF);//0021483 } } @@ -1771,99 +1861,6 @@ void GEOMImpl_IBlocksOperations::AddBlocksFrom (const TopoDS_Shape& theShape, } } -void AddBlocksFromOld (const TopoDS_Shape& theShape, - TopTools_ListOfShape& BLO, - TopTools_ListOfShape& NOT, - TopTools_ListOfShape& DEG, - TopTools_ListOfShape& SEA) -{ - TopAbs_ShapeEnum aType = theShape.ShapeType(); - switch (aType) { - case TopAbs_COMPOUND: - case TopAbs_COMPSOLID: - { - TopoDS_Iterator It (theShape); - for (; It.More(); It.Next()) { - AddBlocksFromOld(It.Value(), BLO, NOT, DEG, SEA); - } - } - break; - case TopAbs_SOLID: - { - TopTools_MapOfShape mapFaces; - TopExp_Explorer expF (theShape, TopAbs_FACE); - Standard_Integer nbFaces = 0; - Standard_Boolean hasNonQuadr = Standard_False; - Standard_Boolean hasDegenerated = Standard_False; - Standard_Boolean hasSeam = Standard_False; - for (; expF.More(); expF.Next()) { - if (mapFaces.Add(expF.Current())) { - nbFaces++; - if (nbFaces > 6) break; - - // Check number of edges in the face - Standard_Integer nbEdges = 0; - TopTools_MapOfShape mapEdges; - - // get wire - TopoDS_Shape aF = expF.Current(); - TopExp_Explorer wires (aF, TopAbs_WIRE); - if (!wires.More()) { - // no wire in the face - hasNonQuadr = Standard_True; - break; - } - TopoDS_Shape aWire = wires.Current(); - wires.Next(); - if (wires.More()) { - // multiple wires in the face - hasNonQuadr = Standard_True; - break; - } - - // iterate on wire - BRepTools_WireExplorer aWE (TopoDS::Wire(aWire), TopoDS::Face(aF)); - for (; aWE.More(); aWE.Next(), nbEdges++) { - if (BRep_Tool::Degenerated(aWE.Current())) { - // degenerated edge found - hasDegenerated = Standard_True; -// break; - } - if (mapEdges.Contains(aWE.Current())) { - // seam edge found - hasSeam = Standard_True; -// break; - } - mapEdges.Add(aWE.Current()); - } - if (nbEdges != 4) { - hasNonQuadr = Standard_True; - } - } - } - if (nbFaces == 6) { - if (hasDegenerated || hasSeam) { - if (hasDegenerated) { - DEG.Append(theShape); - } - if (hasSeam) { - SEA.Append(theShape); - } - } else if (hasNonQuadr) { - NOT.Append(theShape); - } else { - BLO.Append(theShape); - } - } else { - NOT.Append(theShape); - } - } - break; - default: - NOT.Append(theShape); - } -} - #define REL_NOT_CONNECTED 0 #define REL_OK 1 #define REL_NOT_GLUED 2 @@ -2086,158 +2083,6 @@ Standard_Boolean HasAnyConnection (const Standard_Integer theBlockIndex, return Standard_False; } -//============================================================================= -/*! - * CheckCompoundOfBlocksOld - */ -//============================================================================= -Standard_Boolean GEOMImpl_IBlocksOperations::CheckCompoundOfBlocksOld - (Handle(GEOM_Object) theCompound, - std::list& theErrors) -{ - SetErrorCode(KO); - - if (theCompound.IsNull()) return Standard_False; - TopoDS_Shape aBlockOrComp = theCompound->GetValue(); - - Standard_Boolean isCompOfBlocks = Standard_True; - - // Map sub-shapes and their indices - TopTools_IndexedMapOfShape anIndices; - TopExp::MapShapes(aBlockOrComp, anIndices); - - // 1. Report non-blocks - TopTools_ListOfShape NOT; // Not blocks - TopTools_ListOfShape DEG; // Hexahedral solids, having degenerated edges - TopTools_ListOfShape SEA; // Hexahedral solids, having seam edges - TopTools_ListOfShape BLO; // All blocks from the given compound - AddBlocksFromOld(aBlockOrComp, BLO, NOT, DEG, SEA); - - if (NOT.Extent() > 0) { - isCompOfBlocks = Standard_False; - BCError anErr; - anErr.error = NOT_BLOCK; - TopTools_ListIteratorOfListOfShape it (NOT); - for (; it.More(); it.Next()) { - anErr.incriminated.push_back(anIndices.FindIndex(it.Value())); - } - theErrors.push_back(anErr); - } - - if (DEG.Extent() > 0 || SEA.Extent() > 0) { - isCompOfBlocks = Standard_False; - BCError anErr; - anErr.error = EXTRA_EDGE; - - TopTools_ListIteratorOfListOfShape itDEG (DEG); - for (; itDEG.More(); itDEG.Next()) { - anErr.incriminated.push_back(anIndices.FindIndex(itDEG.Value())); - } - - TopTools_ListIteratorOfListOfShape itSEA (SEA); - for (; itSEA.More(); itSEA.Next()) { - anErr.incriminated.push_back(anIndices.FindIndex(itSEA.Value())); - } - - theErrors.push_back(anErr); - } - - Standard_Integer nbBlocks = BLO.Extent(); - if (nbBlocks == 0) { - isCompOfBlocks = Standard_False; - SetErrorCode(OK); - return isCompOfBlocks; - } - if (nbBlocks == 1) { - SetErrorCode(OK); - return isCompOfBlocks; - } - - // Convert list of blocks into array for easy and fast access - Standard_Integer ibl = 1; - TopTools_Array1OfShape aBlocks (1, nbBlocks); - TopTools_ListIteratorOfListOfShape BLOit (BLO); - for (; BLOit.More(); BLOit.Next(), ibl++) { - aBlocks.SetValue(ibl, BLOit.Value()); - } - - // 2. Find relations between all blocks, - // report connection errors (NOT_GLUED and INVALID_CONNECTION) - TColStd_Array2OfInteger aRelations (1, nbBlocks, 1, nbBlocks); - aRelations.Init(REL_NOT_CONNECTED); - - Standard_Integer row = 1; - for (row = 1; row <= nbBlocks; row++) { - TopoDS_Shape aBlock = aBlocks.Value(row); - - Standard_Integer col = row + 1; - for (; col <= nbBlocks; col++) { - Standard_Integer aRel = BlocksRelation(aBlock, aBlocks.Value(col)); - if (aRel != REL_NOT_CONNECTED) { - aRelations.SetValue(row, col, aRel); - aRelations.SetValue(col, row, aRel); - if (aRel == REL_NOT_GLUED) { - // report connection error - isCompOfBlocks = Standard_False; - BCError anErr; - anErr.error = NOT_GLUED; - anErr.incriminated.push_back(anIndices.FindIndex(aBlocks.Value(row))); - anErr.incriminated.push_back(anIndices.FindIndex(aBlocks.Value(col))); - theErrors.push_back(anErr); - } else if (aRel == REL_COLLISION_VV || - aRel == REL_COLLISION_FF || - aRel == REL_COLLISION_EE || - aRel == REL_UNKNOWN) { - // report connection error - isCompOfBlocks = Standard_False; - BCError anErr; - anErr.error = INVALID_CONNECTION; - anErr.incriminated.push_back(anIndices.FindIndex(aBlocks.Value(row))); - anErr.incriminated.push_back(anIndices.FindIndex(aBlocks.Value(col))); - theErrors.push_back(anErr); - } else { - } - } - } - } - - // 3. Find largest set of connected (good connection or not glued) blocks - TColStd_MapOfInteger aProcessedMap; - TColStd_MapOfInteger aLargestSet; - TColStd_MapOfInteger aCurrentSet; - for (ibl = 1; ibl <= nbBlocks; ibl++) { - if (!aProcessedMap.Contains(ibl)) { - aCurrentSet.Clear(); - FindConnected(ibl, aRelations, aProcessedMap, aCurrentSet); - if (aCurrentSet.Extent() > aLargestSet.Extent()) { - aLargestSet = aCurrentSet; - } - } - } - - // 4. Report all blocks, isolated from - BCError anErr; - anErr.error = NOT_CONNECTED; - Standard_Boolean hasIsolated = Standard_False; - for (ibl = 1; ibl <= nbBlocks; ibl++) { - if (!aLargestSet.Contains(ibl)) { - aProcessedMap.Clear(); - if (!HasAnyConnection(ibl, aLargestSet, aRelations, aProcessedMap)) { - // report connection absence - hasIsolated = Standard_True; - anErr.incriminated.push_back(anIndices.FindIndex(aBlocks.Value(ibl))); - } - } - } - if (hasIsolated) { - isCompOfBlocks = Standard_False; - theErrors.push_back(anErr); - } - - SetErrorCode(OK); - return isCompOfBlocks; -} - //============================================================================= /*! * PrintBCErrors @@ -2312,7 +2157,7 @@ Standard_Boolean GEOMImpl_IBlocksOperations::CheckCompoundOfBlocks TopTools_ListOfShape EXT; // Hexahedral solids, having degenerated and/or seam edges TopTools_ListOfShape BLO; // All blocks from the given compound TopTools_ListOfShape NOQ; // All non-quadrangular faces - AddBlocksFrom(aBlockOrComp, BLO, NOT, EXT, NOQ); + AddBlocksFrom(aBlockOrComp, BLO, NOT, EXT, NOQ, -1.); // Report non-blocks if (NOT.Extent() > 0) { @@ -2478,7 +2323,8 @@ Standard_Boolean GEOMImpl_IBlocksOperations::CheckCompoundOfBlocks */ //============================================================================= Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetNonBlocks - (Handle(GEOM_Object) theShape, + (Handle(GEOM_Object) theShape, + const Standard_Real theToleranceC1, Handle(GEOM_Object)& theNonQuads) { SetErrorCode(KO); @@ -2491,7 +2337,7 @@ Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetNonBlocks TopTools_ListOfShape NOT; // Not blocks TopTools_ListOfShape EXT; // Hexahedral solids, having degenerated and/or seam edges TopTools_ListOfShape NOQ; // All non-quadrangular faces - AddBlocksFrom(aShape, BLO, NOT, EXT, NOQ); + AddBlocksFrom(aShape, BLO, NOT, EXT, NOQ, theToleranceC1); if (NOT.IsEmpty() && EXT.IsEmpty() && NOQ.IsEmpty()) { SetErrorCode("NOT_FOUND_ANY"); diff --git a/src/GEOMImpl/GEOMImpl_IBlocksOperations.hxx b/src/GEOMImpl/GEOMImpl_IBlocksOperations.hxx index 8a03b6e23..34162d6ed 100644 --- a/src/GEOMImpl/GEOMImpl_IBlocksOperations.hxx +++ b/src/GEOMImpl/GEOMImpl_IBlocksOperations.hxx @@ -125,16 +125,14 @@ class GEOMImpl_IBlocksOperations : public GEOM_IOperations { std::list incriminated; }; - Standard_EXPORT Standard_Boolean CheckCompoundOfBlocksOld (Handle(GEOM_Object) theCompound, - std::list& theErrors); - Standard_EXPORT Standard_Boolean CheckCompoundOfBlocks (Handle(GEOM_Object) theCompound, std::list& theErrors); Standard_EXPORT TCollection_AsciiString PrintBCErrors (Handle(GEOM_Object) theCompound, const std::list& theErrors); - Standard_EXPORT Handle(GEOM_Object) GetNonBlocks (Handle(GEOM_Object) theShape, + Standard_EXPORT Handle(GEOM_Object) GetNonBlocks (Handle(GEOM_Object) theShape, + const Standard_Real theToleranceC1, Handle(GEOM_Object)& theNonQuads); Standard_EXPORT Handle(GEOM_Object) RemoveExtraEdges (Handle(GEOM_Object) theShape, @@ -148,7 +146,8 @@ class GEOMImpl_IBlocksOperations : public GEOM_IOperations { TopTools_ListOfShape& BLO, TopTools_ListOfShape& NOT, TopTools_ListOfShape& EXT, - TopTools_ListOfShape& NOQ); + TopTools_ListOfShape& NOQ, + const Standard_Real theToleranceC1 = -1.); // Extract blocks from blocks compounds Standard_EXPORT Handle(TColStd_HSequenceOfTransient) ExplodeCompoundOfBlocks diff --git a/src/GEOM_I/GEOM_IBlocksOperations_i.cc b/src/GEOM_I/GEOM_IBlocksOperations_i.cc old mode 100755 new mode 100644 index 55a9c3c70..572cdd7f9 --- a/src/GEOM_I/GEOM_IBlocksOperations_i.cc +++ b/src/GEOM_I/GEOM_IBlocksOperations_i.cc @@ -749,6 +749,7 @@ char* GEOM_IBlocksOperations_i::PrintBCErrors //============================================================================= GEOM::GEOM_Object_ptr GEOM_IBlocksOperations_i::GetNonBlocks (GEOM::GEOM_Object_ptr theShape, + const CORBA::Double theToleranceC1, GEOM::GEOM_Object_out theNonQuads) { GEOM::GEOM_Object_var aGEOMObject; @@ -765,7 +766,8 @@ GEOM::GEOM_Object_ptr GEOM_IBlocksOperations_i::GetNonBlocks //Get the result Handle(GEOM_Object) aFaces; - Handle(GEOM_Object) anObject = GetOperations()->GetNonBlocks(aShape, aFaces); + Handle(GEOM_Object) anObject = + GetOperations()->GetNonBlocks(aShape, theToleranceC1, aFaces); if (!GetOperations()->IsDone()) return aGEOMObject._retn(); diff --git a/src/GEOM_I/GEOM_IBlocksOperations_i.hh b/src/GEOM_I/GEOM_IBlocksOperations_i.hh index fa457b566..482ea8a8e 100644 --- a/src/GEOM_I/GEOM_IBlocksOperations_i.hh +++ b/src/GEOM_I/GEOM_IBlocksOperations_i.hh @@ -122,6 +122,7 @@ class GEOM_I_EXPORT GEOM_IBlocksOperations_i : const GEOM::GEOM_IBlocksOperations::BCErrors& theErrors); GEOM::GEOM_Object_ptr GetNonBlocks (GEOM::GEOM_Object_ptr theShape, + const CORBA::Double theToleranceC1, GEOM::GEOM_Object_out theNonQuads); GEOM::GEOM_Object_ptr RemoveExtraEdges (GEOM::GEOM_Object_ptr theShape, diff --git a/src/GEOM_SWIG/geomBuilder.py b/src/GEOM_SWIG/geomBuilder.py index 93e6da907..652b4173b 100644 --- a/src/GEOM_SWIG/geomBuilder.py +++ b/src/GEOM_SWIG/geomBuilder.py @@ -80,7 +80,7 @@ ## # create and publish cylinder ## cyl = geompy.MakeCylinderRH(100, 100, "cylinder") ## # get non blocks from cylinder -## g1, g2 = geompy.GetNonBlocks(cyl, "nonblock") +## g1, g2 = geompy.GetNonBlocks(cyl, theName="nonblock") ## @endcode ## ## Above example will publish both result compounds (first with non-hexa solids and @@ -88,7 +88,7 @@ ## However, if second command is invoked as ## ## @code -## g1, g2 = geompy.GetNonBlocks(cyl, ("nonhexa", "nonquad")) +## g1, g2 = geompy.GetNonBlocks(cyl, theName=("nonhexa", "nonquad")) ## @endcode ## ## ... the first compound will be published with "nonhexa" name, and second will be named "nonquad". @@ -11431,6 +11431,12 @@ class geomBuilder(object, GEOM._objref_GEOM_Gen): ## Retrieve all non blocks solids and faces from \a theShape. # @param theShape The shape to explore. + # @param theIsUseC1 Flag to check if there are 4 bounds on a face + # taking into account C1 continuity. + # @param theAngTolerance the angular tolerance to check if two neighbor + # edges are codirectional in the common vertex with this + # tolerance. This parameter is used only if + # theIsUseC1 is set to True. # @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. @@ -11438,17 +11444,27 @@ class geomBuilder(object, GEOM._objref_GEOM_Gen): # @return A tuple of two GEOM_Objects. The first object is a group of all # non block solids (= not 6 faces, or with 6 faces, but with the # presence of non-quadrangular faces). The second object is a - # group of all non quadrangular faces. + # group of all non quadrangular faces (= faces with more then + # 1 wire or, if theIsUseC1 is set to True, faces + # with 1 wire with not 4 edges that do not form 4 bounds of + # C1 continuity). # # @ref tui_measurement_tools_page "Example 1" # \n @ref swig_GetNonBlocks "Example 2" @ManageTransactions("BlocksOp") - def GetNonBlocks (self, theShape, theName=None): + def GetNonBlocks (self, theShape, theIsUseC1 = False, + theAngTolerance = 1.e-12, theName=None): """ Retrieve all non blocks solids and faces from theShape. Parameters: theShape The shape to explore. + theIsUseC1 Flag to check if there are 4 bounds on a face + taking into account C1 continuity. + theAngTolerance the angular tolerance to check if two neighbor + edges are codirectional in the common vertex with this + tolerance. This parameter is used only if + theIsUseC1 is set to True. 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. @@ -11457,13 +11473,19 @@ class geomBuilder(object, GEOM._objref_GEOM_Gen): A tuple of two GEOM_Objects. The first object is a group of all non block solids (= not 6 faces, or with 6 faces, but with the presence of non-quadrangular faces). The second object is a - group of all non quadrangular faces. + group of all non quadrangular faces (= faces with more then + 1 wire or, if theIsUseC1 is set to True, faces + with 1 wire with not 4 edges that do not form 4 bounds of + C1 continuity). Usage: (res_sols, res_faces) = geompy.GetNonBlocks(myShape1) """ # Example: see GEOM_Spanner.py - aTuple = self.BlocksOp.GetNonBlocks(theShape) + aTolerance = -1.0 + if theIsUseC1: + aTolerance = theAngTolerance + aTuple = self.BlocksOp.GetNonBlocks(theShape, aTolerance) RaiseIfFailed("GetNonBlocks", self.BlocksOp) self._autoPublish(aTuple, theName, ("groupNonHexas", "groupNonQuads")) return aTuple diff --git a/src/MeasureGUI/MeasureGUI_GetNonBlocksDlg.cxx b/src/MeasureGUI/MeasureGUI_GetNonBlocksDlg.cxx index 5c04f273a..6ef248017 100644 --- a/src/MeasureGUI/MeasureGUI_GetNonBlocksDlg.cxx +++ b/src/MeasureGUI/MeasureGUI_GetNonBlocksDlg.cxx @@ -25,7 +25,6 @@ #include "MeasureGUI_GetNonBlocksDlg.h" -#include #include #include @@ -33,9 +32,18 @@ #include #include #include +#include #include #include +#include +#include +#include +#include +#include +#include +#include + //================================================================================= // class : MeasureGUI_GetNonBlocksDlg() // purpose : Constructs a MeasureGUI_GetNonBlocksDlg which is a child of 'parent', @@ -44,7 +52,12 @@ // true to construct a modal dialog. //================================================================================= MeasureGUI_GetNonBlocksDlg::MeasureGUI_GetNonBlocksDlg (GeometryGUI* theGeometryGUI, QWidget* parent) - : GEOMBase_Skeleton(theGeometryGUI, parent, false) + : GEOMBase_Skeleton(theGeometryGUI, parent, false), + myObjectName (0), + mySelButton (0), + myUseC1Check (0), + myTolLbl (0), + mySpinTol (0) { QPixmap image0 (SUIT_Session::session()->resourceMgr()->loadPixmap("GEOM", tr("ICON_DLG_GETNONBLOCKS"))); QPixmap image1 (SUIT_Session::session()->resourceMgr()->loadPixmap("GEOM", tr("ICON_SELECT"))); @@ -58,16 +71,36 @@ MeasureGUI_GetNonBlocksDlg::MeasureGUI_GetNonBlocksDlg (GeometryGUI* theGeometry mainFrame()->RadioButton2->close(); mainFrame()->RadioButton3->setAttribute(Qt::WA_DeleteOnClose); mainFrame()->RadioButton3->close(); - - myGrp = new DlgRef_1Sel (centralWidget()); - myGrp->GroupBox1->setTitle(tr("GEOM_GETNONBLOCKS")); - myGrp->TextLabel1->setText(tr("GEOM_OBJECT")); - myGrp->PushButton1->setIcon(image1); - myGrp->LineEdit1->setReadOnly(true); + + QGroupBox *aGrpParams = + new QGroupBox(tr("GEOM_GETNONBLOCKS"), centralWidget()); + QGridLayout *aParamsLayout = new QGridLayout(aGrpParams); + QLabel *anObjLbl = new QLabel(tr("GEOM_OBJECT"), aGrpParams); + + myObjectName = new QLineEdit(aGrpParams); + mySelButton = new QPushButton(aGrpParams); + myUseC1Check = new QCheckBox(tr("GEOM_USE_C1_CRITERION"), aGrpParams); + myTolLbl = new QLabel(tr("GEOM_ANGULAR_TOLERANCE"), aGrpParams); + mySpinTol = new SalomeApp_DoubleSpinBox(aGrpParams); + + myObjectName->setReadOnly(true); + mySelButton->setIcon(image1); + mySelButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + myUseC1Check->setText(tr("GEOM_USE_C1_CRITERION")); + myUseC1Check->setChecked(true); + + aParamsLayout->setMargin(9); + aParamsLayout->setSpacing(6); + aParamsLayout->addWidget(anObjLbl, 0, 0); + aParamsLayout->addWidget(mySelButton, 0, 1); + aParamsLayout->addWidget(myObjectName, 0, 2); + aParamsLayout->addWidget(myUseC1Check, 1, 0, 1, 3); + aParamsLayout->addWidget(myTolLbl, 2, 0); + aParamsLayout->addWidget(mySpinTol, 2, 1, 1, 2); QVBoxLayout* layout = new QVBoxLayout(centralWidget()); layout->setMargin(0); layout->setSpacing(6); - layout->addWidget(myGrp); + layout->addWidget(aGrpParams); /***************************************************************/ @@ -94,14 +127,20 @@ void MeasureGUI_GetNonBlocksDlg::Init() showOnlyPreviewControl(); /* init variables */ - myEditCurrentArgument = myGrp->LineEdit1; + double SpecificStep = 0.0001; + double aDefaultTol = Precision::Angular(); - /* signals and slots connections */ - connect(buttonOk(), SIGNAL(clicked()), this, SLOT(ClickOnOk())); - connect(buttonApply(), SIGNAL(clicked()), this, SLOT(ClickOnApply())); + initSpinBox(mySpinTol, aDefaultTol, MAX_NUMBER, SpecificStep, "ang_tol_precision"); + mySpinTol->setValue(aDefaultTol); + myEditCurrentArgument = myObjectName; - connect(myGrp->LineEdit1, SIGNAL(returnPressed()), this, SLOT(LineEditReturnPressed())); - connect(myGrp->PushButton1, SIGNAL(clicked()), this, SLOT(SetEditCurrentArgument())); + /* signals and slots connections */ + connect(buttonOk(), SIGNAL(clicked()), this, SLOT(ClickOnOk())); + connect(buttonApply(), SIGNAL(clicked()), this, SLOT(ClickOnApply())); + connect(myUseC1Check, SIGNAL(clicked()), this, SLOT(SetUseC1Tolerance())); + connect(mySpinTol, SIGNAL(valueChanged(double)), this, SLOT(processPreview())); + connect(myObjectName, SIGNAL(returnPressed()), this, SLOT(LineEditReturnPressed())); + connect(mySelButton, SIGNAL(clicked()), this, SLOT(SetEditCurrentArgument())); connect(((SalomeApp_Application*)(SUIT_Session::session()->activeApplication()))->selectionMgr(), SIGNAL(currentSelectionChanged()), this, SLOT(SelectionIntoArgument())); @@ -171,11 +210,22 @@ void MeasureGUI_GetNonBlocksDlg::SelectionIntoArgument() //================================================================================= void MeasureGUI_GetNonBlocksDlg::SetEditCurrentArgument() { - myGrp->LineEdit1->setFocus(); - myEditCurrentArgument = myGrp->LineEdit1; + myObjectName->setFocus(); + myEditCurrentArgument = myObjectName; SelectionIntoArgument(); } +//================================================================================= +// function : SetUseC1Tolerance() +// purpose : +//================================================================================= +void MeasureGUI_GetNonBlocksDlg::SetUseC1Tolerance() +{ + myTolLbl->setEnabled(myUseC1Check->isChecked()); + mySpinTol->setEnabled(myUseC1Check->isChecked()); + processPreview(); +} + //================================================================================= // function : LineEditReturnPressed() // purpose : @@ -183,8 +233,8 @@ void MeasureGUI_GetNonBlocksDlg::SetEditCurrentArgument() void MeasureGUI_GetNonBlocksDlg::LineEditReturnPressed() { QLineEdit* send = (QLineEdit*)sender(); - if (send == myGrp->LineEdit1) { - myEditCurrentArgument = myGrp->LineEdit1; + if (send == myObjectName) { + myEditCurrentArgument = myObjectName; GEOMBase_Skeleton::LineEditReturnPressed(); } } @@ -211,10 +261,11 @@ void MeasureGUI_GetNonBlocksDlg::ActivateThisDialog() void MeasureGUI_GetNonBlocksDlg::processObject() { if (myObj->_is_nil()) { + myObjectName->setText(""); erasePreview(); } else { - myGrp->LineEdit1->setText(GEOMBase::GetName(myObj)); + myObjectName->setText(GEOMBase::GetName(myObj)); processPreview(); } @@ -243,9 +294,9 @@ GEOM::GEOM_IOperations_ptr MeasureGUI_GetNonBlocksDlg::createOperation() // function : isValid // purpose : //================================================================================= -bool MeasureGUI_GetNonBlocksDlg::isValid (QString&) +bool MeasureGUI_GetNonBlocksDlg::isValid (QString &msg) { - return !myObj->_is_nil(); + return !myObj->_is_nil() && mySpinTol->isValid(msg, !IsPreview()); } //================================================================================= @@ -256,7 +307,13 @@ bool MeasureGUI_GetNonBlocksDlg::execute (ObjectList& objects) { GEOM::GEOM_IBlocksOperations_var anOper = GEOM::GEOM_IBlocksOperations::_narrow(getOperation()); GEOM::GEOM_Object_var aNonQuads; - GEOM::GEOM_Object_var anObj = anOper->GetNonBlocks(myObj, aNonQuads); + double aC1Tol = -1.; + + if (myUseC1Check->isChecked()) { + aC1Tol = mySpinTol->value(); + } + + GEOM::GEOM_Object_var anObj = anOper->GetNonBlocks(myObj, aC1Tol, aNonQuads); //mainFrame()->ResultName->setText(tr("GEOM_NONBLOCKS")); if (!anObj->_is_nil()) diff --git a/src/MeasureGUI/MeasureGUI_GetNonBlocksDlg.h b/src/MeasureGUI/MeasureGUI_GetNonBlocksDlg.h index 5282c8cd6..f6f59b680 100644 --- a/src/MeasureGUI/MeasureGUI_GetNonBlocksDlg.h +++ b/src/MeasureGUI/MeasureGUI_GetNonBlocksDlg.h @@ -28,7 +28,11 @@ #include -class DlgRef_1Sel; +class QCheckBox; +class QLabel; +class QLineEdit; +class QPushButton; +class SalomeApp_DoubleSpinBox; //================================================================================= // class : MeasureGUI_GetNonBlocksDlg @@ -45,7 +49,7 @@ public: protected: // redefined from GEOMBase_Helper virtual GEOM::GEOM_IOperations_ptr createOperation(); - virtual bool isValid (QString&); + virtual bool isValid (QString &msg); virtual bool execute (ObjectList&); virtual GEOM::GEOM_Object_ptr getFather (GEOM::GEOM_Object_ptr); @@ -56,6 +60,7 @@ private slots: void LineEditReturnPressed(); void SelectionIntoArgument(); void SetEditCurrentArgument(); + void SetUseC1Tolerance(); private: void Init(); @@ -64,7 +69,11 @@ private: private: GEOM::GEOM_Object_var myObj; - DlgRef_1Sel* myGrp; + QLineEdit *myObjectName; + QPushButton *mySelButton; + QCheckBox *myUseC1Check; + QLabel *myTolLbl; + SalomeApp_DoubleSpinBox *mySpinTol; }; #endif // MEASUREGUI_GETNONBLOCKSDLG_H