From: eap Date: Wed, 28 Jul 2021 17:36:57 +0000 (+0300) Subject: bos #16292 [CEA 656] MGCADSurf: option SetEnforced1D mesh X-Git-Tag: V9_8_0a1~8 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=0a057ad10d10cbec461c916216f468dbe94390c7;p=plugins%2Fblsurfplugin.git bos #16292 [CEA 656] MGCADSurf: option SetEnforced1D mesh --- diff --git a/doc/salome/examples/blsurfdemo.py b/doc/salome/examples/blsurfdemo.py index 4cb045d..ad4e0d6 100644 --- a/doc/salome/examples/blsurfdemo.py +++ b/doc/salome/examples/blsurfdemo.py @@ -108,12 +108,33 @@ algo2d.SetAttractorGeom(Face_2, Wire_1, 1, 36.641, 20, 10) # the gradation to its maximum algo2d.SetGradation( 2.5 ) +# ----------------------- +# Adding enforced meshes +# ----------------------- + +# create 1D mesh +OZ = geompy.MakeVectorDXDYDZ(0, 0, 1) +circle_1 = geompy.MakeCircle( geompy.MakeVertex( 100, 75, 200 ), OZ, 50 ) +circle_2 = geompy.MakeCircle( geompy.MakeVertex( 100, 150, 200 ), OZ, 70 ) +circles = geompy.MakeCompound([ circle_1, circle_2 ], theName="circles") +mesh_1D = smesh.Mesh( circles, "enforced circles" ) +mesh_1D.Segment().LocalLength( 7 ) +mesh_1D.Compute() + +# Add enforced mesh +algo2d.SetEnforcedMeshes([ + smeshBuilder.MG_EnforcedMesh1D( mesh_1D, "Enforced edges")]) + +# ----------------- # compute the mesh +# ----------------- + cadsurfMesh.Compute() -# --------------------------------------------------------------- + +# ================================================================ # blsurf_construct_mesh_internal_vertices Using internal vertices -# --------------------------------------------------------------- +# ================================================================ # Creating a geometry containing internal vertices Face_3 = geompy.MakeFaceHW(1, 1, 1) diff --git a/doc/salome/gui/BLSURFPLUGIN/images/blsurf_enforced_meshes.png b/doc/salome/gui/BLSURFPLUGIN/images/blsurf_enforced_meshes.png new file mode 100644 index 0000000..cbc928e Binary files /dev/null and b/doc/salome/gui/BLSURFPLUGIN/images/blsurf_enforced_meshes.png differ diff --git a/doc/salome/gui/BLSURFPLUGIN/input/blsurf_hypo.doc b/doc/salome/gui/BLSURFPLUGIN/input/blsurf_hypo.doc index 1b1c1d5..fefba64 100644 --- a/doc/salome/gui/BLSURFPLUGIN/input/blsurf_hypo.doc +++ b/doc/salome/gui/BLSURFPLUGIN/input/blsurf_hypo.doc @@ -392,6 +392,21 @@ A group can optionnaly be defined on those enforced vertices. \ref blsurf_top "Back to top" +\section blsurf_enforced_meshes Enforced Meshes + +\image html blsurf_enforced_meshes.png + +MG-CADSurf algorithm can be forced by other 1D meshes, sub-meshes or +groups. 1D meshes are allowed to pass over face boundaries and to +intersect other enforced meshes. +If a group name is given, the enforced 1D elements will be added to the group. +If the group does not exist, it is created. + +\sa Sample TUI Script of the \ref tui_blsurf "creation of a MG-CADSurf hypothesis", including enforced meshes. + +\ref blsurf_top "Back to top" + + \section blsurf_periodicity Periodicity \subsection periodicity_introduction Introduction diff --git a/idl/BLSURFPlugin_Algorithm.idl b/idl/BLSURFPlugin_Algorithm.idl index 7e3bd78..e380f2f 100644 --- a/idl/BLSURFPlugin_Algorithm.idl +++ b/idl/BLSURFPlugin_Algorithm.idl @@ -26,9 +26,10 @@ #ifndef _SMESH_BLSURFALGORITHM_IDL_ #define _SMESH_BLSURFALGORITHM_IDL_ -#include "SMESH_Hypothesis.idl" #include "GEOM_Gen.idl" #include "SALOME_Exception.idl" +#include "SMESH_Hypothesis.idl" +#include "SMESH_Mesh.idl" /*! * BLSURFPlugin: interfaces to BLSURF related hypotheses and algorithms @@ -37,6 +38,14 @@ module BLSURFPlugin { typedef sequence string_array; + // Enforced 1D Mesh + struct MG_EnforcedMesh1D + { + SMESH::SMESH_IDSource mesh; // mesh, group or sub-mesh + string groupName; // optional name of a group to add mesh edges to + }; + typedef sequence< MG_EnforcedMesh1D > EnforcedMeshesList; + // Enforced vertex name typedef string TEnfName; // Entry @@ -44,12 +53,12 @@ module BLSURFPlugin typedef sequence TEntryList; // Group name typedef string TEnfGroupName; - + // Coordinates of enforced vertex typedef sequence TEnfVertexCoords; // List of coords typedef sequence TEnfVertexCoordsList; - + // Enforced vertex struct TEnfVertex { TEnfName name; @@ -358,11 +367,17 @@ module BLSURFPlugin double GetVolumeProximityRatio(); /*! - *Set verbosity level in the range 0 to 100. + * Set verbosity level in the range 0 to 100. */ void SetVerbosity(in short theVal) raises (SALOME::SALOME_Exception); short GetVerbosity(); + /*! + * Set/Get enforced 1D meshes + */ + void SetEnforcedMeshes( in EnforcedMeshesList enforcedMeshes ); + EnforcedMeshesList GetEnforcedMeshes(); + /*! * Set enforce_cad_edge_sizes parameter * diff --git a/src/BLSURFPlugin/BLSURFPluginBuilder.py b/src/BLSURFPlugin/BLSURFPluginBuilder.py index ac507f2..8a7e946 100644 --- a/src/BLSURFPlugin/BLSURFPluginBuilder.py +++ b/src/BLSURFPlugin/BLSURFPluginBuilder.py @@ -42,6 +42,8 @@ BLSURF_Custom, BLSURF_GlobalSize, BLSURF_LocalSize = MG_CADSURF_Custom, MG_CADSU noBLSURFPlugin = 0 try: import BLSURFPlugin + from BLSURFPlugin import MG_EnforcedMesh1D + except ImportError: noBLSURFPlugin = 1 pass @@ -652,6 +654,21 @@ class BLSURF_Algorithm(Mesh_Algorithm): def GetInternalEnforcedVertexAllFacesGroup(self): return self.Parameters().GetInternalEnforcedVertexAllFacesGroup() + #----------------------------------------- + # Enforced mesh + #----------------------------------------- + + ## Set enforced 1D meshes + # @param enfMeshes : list of smeshBuilder.MG_EnforcedMesh1D structures + # + # Example: cadsurf.SetEnforcedMeshes([ smeshBuilder.MG_EnforcedMesh1D( mesh1D, "Group 1D")] + def SetEnforcedMeshes( self, enfMeshes ): + from salome.smesh.smeshBuilder import Mesh + for em in enfMeshes: + if isinstance( em.mesh, Mesh ): + em.mesh = em.mesh.GetMesh() + return self.Parameters().SetEnforcedMeshes( enfMeshes ) + #----------------------------------------- # Attractors #----------------------------------------- diff --git a/src/BLSURFPlugin/BLSURFPlugin_BLSURF.cxx b/src/BLSURFPlugin/BLSURFPlugin_BLSURF.cxx index 6bd3f2d..14b9f4b 100644 --- a/src/BLSURFPlugin/BLSURFPlugin_BLSURF.cxx +++ b/src/BLSURFPlugin/BLSURFPlugin_BLSURF.cxx @@ -25,21 +25,19 @@ // --- #include "BLSURFPlugin_BLSURF.hxx" -#include "BLSURFPlugin_Hypothesis.hxx" + #include "BLSURFPlugin_Attractor.hxx" +#include "BLSURFPlugin_EnforcedMesh1D.hxx" +#include "BLSURFPlugin_Hypothesis.hxx" extern "C"{ #include #include } -#include - - -#include - #include #include +#include #include #include #include @@ -47,15 +45,17 @@ extern "C"{ #include #include #include -#include +#include #include +#include #include #include -#include #include -#include +#include + +#include // python // OPENCASCADE includes #include @@ -405,14 +405,12 @@ status_t size_on_surface(integer face_id, real *uv, real *size, void *user_data) status_t size_on_edge(integer edge_id, real t, real *size, void *user_data); status_t size_on_vertex(integer vertex_id, real *size, void *user_data); -typedef struct { - gp_XY uv; - gp_XYZ xyz; -} projectionPoint; - ///////////////////////////////////////////////////////// -projectionPoint getProjectionPoint(TopoDS_Face& theFace, const gp_Pnt& thePoint) +BLSURFPlugin_BLSURF::projectionPoint +BLSURFPlugin_BLSURF::getProjectionPoint(TopoDS_Face& theFace, + const gp_Pnt& thePoint, + const bool theAllowStateON) { projectionPoint myPoint; @@ -444,12 +442,13 @@ projectionPoint getProjectionPoint(TopoDS_Face& theFace, const gp_Pnt& thePoint) { if ( !foundFace.IsNull() ) return myPoint; // thePoint seems to be TopAbs_ON - foundFace = face; - myPoint.uv = uv.XY(); - myPoint.xyz = surface->Value( uv ).XYZ(); + foundFace = face; + myPoint.uv = uv.XY(); + myPoint.xyz = surface->Value( uv ).XYZ(); + myPoint.state = FC.State(); // break; } - if ( FC.State() == TopAbs_ON ) + if ( FC.State() == TopAbs_ON && !theAllowStateON ) return myPoint; } } @@ -462,12 +461,15 @@ projectionPoint getProjectionPoint(TopoDS_Face& theFace, const gp_Pnt& thePoint) const TopoDS_Face& face = d2f->second.first; const gp_Pnt2d & uv = d2f->second.second; BRepClass_FaceClassifier FC( face, uv, Precision::Confusion()); - if ( FC.State() == TopAbs_IN ) + if (( FC.State() == TopAbs_IN ) || + ( FC.State() == TopAbs_ON && theAllowStateON )) { - foundFace = face; - myPoint.uv = uv.XY(); - myPoint.xyz = theHelper->GetSurface( face )->Value( uv ).XYZ(); - break; + foundFace = face; + myPoint.uv = uv.XY(); + myPoint.xyz = theHelper->GetSurface( face )->Value( uv ).XYZ(); + myPoint.state = FC.State(); + if ( FC.State() == TopAbs_IN ) + break; } } } @@ -477,7 +479,7 @@ projectionPoint getProjectionPoint(TopoDS_Face& theFace, const gp_Pnt& thePoint) // "getProjectionPoint: can't find a face by a vertex"); theFace = TopoDS::Face( foundFace ); } - else + else // !theFace.IsNull() { Handle(Geom_Surface) surface = BRep_Tool::Surface( theFace ); GeomAPI_ProjectPointOnSurf projector( thePoint, surface ); @@ -487,12 +489,14 @@ projectionPoint getProjectionPoint(TopoDS_Face& theFace, const gp_Pnt& thePoint) Standard_Real u,v; projector.LowerDistanceParameters(u,v); - myPoint.uv = gp_XY(u,v); - gp_Pnt aPnt = projector.NearestPoint(); - myPoint.xyz = gp_XYZ(aPnt.X(),aPnt.Y(),aPnt.Z()); + myPoint.uv = gp_XY(u,v); + myPoint.xyz = projector.NearestPoint().XYZ(); BRepClass_FaceClassifier FC( theFace, myPoint.uv, Precision::Confusion()); - if ( FC.State() != TopAbs_IN ) + myPoint.state = FC.State(); + + if (( FC.State() != TopAbs_IN ) && + ( FC.State() != TopAbs_ON || !theAllowStateON )) theFace.Nullify(); } @@ -502,16 +506,8 @@ projectionPoint getProjectionPoint(TopoDS_Face& theFace, const gp_Pnt& thePoint) ///////////////////////////////////////////////////////// TopoDS_Shape BLSURFPlugin_BLSURF::entryToShape(std::string entry) { - GEOM::GEOM_Object_var aGeomObj; - TopoDS_Shape S = TopoDS_Shape(); - SALOMEDS::SObject_var aSObj = SMESH_Gen_i::GetSMESHGen()->getStudyServant()->FindObjectID( entry.c_str() ); - if (!aSObj->_is_nil()) { - CORBA::Object_var obj = aSObj->GetObject(); - aGeomObj = GEOM::GEOM_Object::_narrow(obj); - aSObj->UnRegister(); - } - if ( !aGeomObj->_is_nil() ) - S = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( aGeomObj.in() ); + GEOM::GEOM_Object_var aGeomObj = SMESH_Gen_i::GetSMESHGen()->GetGeomObjectByEntry( entry ); + TopoDS_Shape S = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( aGeomObj ); return S; } @@ -520,7 +516,8 @@ void _createEnforcedVertexOnFace(TopoDS_Face faceShape, gp_Pnt aPnt, BLSURFPlugi BLSURFPlugin_Hypothesis::TEnfVertexCoords enf_coords, coords, s_coords; // Find the face and get the (u,v) values of the enforced vertex on the face - projectionPoint myPoint = getProjectionPoint(faceShape,aPnt); + BLSURFPlugin_BLSURF::projectionPoint myPoint = + BLSURFPlugin_BLSURF::getProjectionPoint(faceShape,aPnt); if ( faceShape.IsNull() ) return; @@ -639,30 +636,30 @@ void createAttractorOnFace(TopoDS_Shape GeomShape, std::string AttractorFunction // xa pos1 = AttractorFunction.find(sep); if (pos1!=string::npos) - xa = atof(AttractorFunction.substr(10, pos1-10).c_str()); + xa = atof(AttractorFunction.substr(10, pos1-10).c_str()); // ya pos2 = AttractorFunction.find(sep, pos1+1); if (pos2!=string::npos) { - ya = atof(AttractorFunction.substr(pos1+1, pos2-pos1-1).c_str()); - pos1 = pos2; + ya = atof(AttractorFunction.substr(pos1+1, pos2-pos1-1).c_str()); + pos1 = pos2; } // za pos2 = AttractorFunction.find(sep, pos1+1); if (pos2!=string::npos) { - za = atof(AttractorFunction.substr(pos1+1, pos2-pos1-1).c_str()); - pos1 = pos2; + za = atof(AttractorFunction.substr(pos1+1, pos2-pos1-1).c_str()); + pos1 = pos2; } // a pos2 = AttractorFunction.find(sep, pos1+1); if (pos2!=string::npos) { - a = atof(AttractorFunction.substr(pos1+1, pos2-pos1-1).c_str()); - pos1 = pos2; + a = atof(AttractorFunction.substr(pos1+1, pos2-pos1-1).c_str()); + pos1 = pos2; } // b pos2 = AttractorFunction.find(sep, pos1+1); if (pos2!=string::npos) { - b = atof(AttractorFunction.substr(pos1+1, pos2-pos1-1).c_str()); - pos1 = pos2; + b = atof(AttractorFunction.substr(pos1+1, pos2-pos1-1).c_str()); + pos1 = pos2; } // createNode pos2 = AttractorFunction.find(sep, pos1+1); @@ -674,13 +671,14 @@ void createAttractorOnFace(TopoDS_Shape GeomShape, std::string AttractorFunction // d pos2 = AttractorFunction.find(")"); if (pos2!=string::npos) { - d = atof(AttractorFunction.substr(pos1+1, pos2-pos1-1).c_str()); + d = atof(AttractorFunction.substr(pos1+1, pos2-pos1-1).c_str()); } // Get the (u,v) values of the attractor on the face - projectionPoint myPoint = getProjectionPoint(TopoDS::Face(GeomShape),gp_Pnt(xa,ya,za)); - gp_XY uvPoint = myPoint.uv; - gp_XYZ xyzPoint = myPoint.xyz; + BLSURFPlugin_BLSURF::projectionPoint myPoint = + BLSURFPlugin_BLSURF::getProjectionPoint(TopoDS::Face(GeomShape),gp_Pnt(xa,ya,za)); + gp_XY uvPoint = myPoint.uv; + gp_XYZ xyzPoint = myPoint.xyz; Standard_Real u0 = uvPoint.X(); Standard_Real v0 = uvPoint.Y(); Standard_Real x0 = xyzPoint.X(); @@ -1931,10 +1929,14 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh& aMesh, SMESHDS_Mesh* meshDS = aMesh.GetMeshDS(); SMESH_MesherHelper helper( aMesh ), helperWithShape( aMesh ); - myHelper = theHelper = & helperWithShape; + theHelper = & helperWithShape; // do not call helper.IsQuadraticSubMesh() because sub-meshes // may be cleaned and helper.myTLinkNodeMap gets invalid in such a case bool haveQuadraticSubMesh = helperWithShape.IsQuadraticSubMesh( aShape ); + haveQuadraticSubMesh = haveQuadraticSubMesh || (_hypothesis && _hypothesis->GetQuadraticMesh()); + helper.SetIsQuadratic( haveQuadraticSubMesh ); + helperWithShape.SetIsQuadratic( haveQuadraticSubMesh ); + bool quadraticSubMeshAndViscousLayer = false; bool needMerge = false; typedef set< SMESHDS_SubMesh*, ShapeTypeCompare > TSubMeshSet; @@ -1947,6 +1949,8 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh& aMesh, TopTools_IndexedDataMapOfShapeListOfShape e2ffmap; TopExp::MapShapesAndAncestors( aShape, TopAbs_EDGE, TopAbs_FACE, e2ffmap ); + BLSURFPlugin_EnforcedMesh1D enforcedMesh( helperWithShape, _hypothesis ); + // Issue 0019864. On DebianSarge, FE signals do not obey to OSD::SetSignal(false) #ifndef WIN32 feclearexcept( FE_ALL_EXCEPT ); @@ -1988,9 +1992,6 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh& aMesh, SetParameters(_hypothesis, css, aShape); - haveQuadraticSubMesh = haveQuadraticSubMesh || (_hypothesis != NULL && _hypothesis->GetQuadraticMesh()); - helper.SetIsQuadratic( haveQuadraticSubMesh ); - // To remove as soon as quadratic mesh is allowed - BEGIN // GDD: Viscous layer is not allowed with quadratic mesh if (_haveViscousLayers && haveQuadraticSubMesh ) { @@ -2030,8 +2031,8 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh& aMesh, { TopoDS_Face f = TopoDS::Face(face_iter.Current()); - SMESH_subMesh* fSM = aMesh.GetSubMesh( f ); - if ( !fSM->IsEmpty() ) continue; // skip already meshed FACE with viscous layers + //SMESH_subMesh* fSM = aMesh.GetSubMesh( f ); + //if ( !fSM->IsEmpty() ) continue; // skip already meshed FACE with viscous layers // make INTERNAL face oriented FORWARD (issue 0020993) if (f.Orientation() != TopAbs_FORWARD && f.Orientation() != TopAbs_REVERSED ) @@ -2088,35 +2089,29 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh& aMesh, } // Specific size map = Attractor - std::map >::iterator attractor_iter = FaceId2AttractorCoords.begin(); - - for (; attractor_iter != FaceId2AttractorCoords.end(); ++attractor_iter) { - if (attractor_iter->first == faceKey) + std::map >::iterator attractor_iter = + FaceId2AttractorCoords.find( faceKey ); + if (attractor_iter != FaceId2AttractorCoords.end() ) + { + double * xyzCoords = & attractor_iter->second[2]; + gp_Pnt P(xyzCoords[0],xyzCoords[1],xyzCoords[2]); + BRepClass_FaceClassifier scl(f,P,1e-7); + TopAbs_State result = scl.State(); + if ( result == TopAbs_OUT ) + MESSAGE("Point is out of face: node is not created"); + if ( result == TopAbs_UNKNOWN ) + MESSAGE("Point position on face is unknown: node is not created"); + if ( result == TopAbs_ON ) + MESSAGE("Point is on border of face: node is not created"); + if ( result == TopAbs_IN ) { - double xyzCoords[3] = {attractor_iter->second[2], - attractor_iter->second[3], - attractor_iter->second[4]}; - - gp_Pnt P(xyzCoords[0],xyzCoords[1],xyzCoords[2]); - BRepClass_FaceClassifier scl(f,P,1e-7); - scl.Perform(f, P, 1e-7); - TopAbs_State result = scl.State(); - if ( result == TopAbs_OUT ) - MESSAGE("Point is out of face: node is not created"); - if ( result == TopAbs_UNKNOWN ) - MESSAGE("Point position on face is unknown: node is not created"); - if ( result == TopAbs_ON ) - MESSAGE("Point is on border of face: node is not created"); - if ( result == TopAbs_IN ) - { - // Point is inside face and not on border - double uvCoords[2] = {attractor_iter->second[0],attractor_iter->second[1]}; - ienf++; - cad_point_t* point_p = cad_point_new(fce, ienf, uvCoords); - cad_point_set_tag(point_p, ienf); - } - FaceId2AttractorCoords.erase(faceKey); + // Point is inside face and not on border + double * uvCoords = & attractor_iter->second[0]; + ienf++; + cad_point_t* point_p = cad_point_new(fce, ienf, uvCoords); + cad_point_set_tag(point_p, ienf); } + FaceId2AttractorCoords.erase(faceKey); } // ----------------- @@ -2182,19 +2177,24 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh& aMesh, EDGES now create the edges associated to this face *****************************************************************************************/ - int edgeKey = -1; - for (TopExp_Explorer edge_iter(f,TopAbs_EDGE);edge_iter.More();edge_iter.Next()) + + std::vector< TopoDS_Edge > edges; + for ( TopExp_Explorer edge_iter( f, TopAbs_EDGE ); edge_iter.More(); edge_iter.Next() ) { - TopoDS_Edge e = TopoDS::Edge(edge_iter.Current()); - int ic = emap.FindIndex(e); - if (ic <= 0) - ic = emap.Add(e); + const TopoDS_Edge& e = TopoDS::Edge( edge_iter.Current() ); + if ( !enforcedMesh.GetSplitsOfEdge( e, edges, emap )) + edges.push_back( e ); + } + for ( const TopoDS_Edge& e : edges ) + { + int ic = emap.Add(e); double tmin,tmax; curves.push_back(BRep_Tool::CurveOnSurface(e, f, tmin, tmax)); - if (HasSizeMapOnEdge){ - edgeKey = EdgesWithSizeMap.FindIndex(e); + if ( HasSizeMapOnEdge ) + { + int edgeKey = EdgesWithSizeMap.FindIndex(e); if (EdgeId2SizeMap.find(edgeKey)!=EdgeId2SizeMap.end()) { theSizeMapStr = EdgeId2SizeMap[edgeKey]; @@ -2256,6 +2256,7 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh& aMesh, The following call sets it to the same value as the edge_id : */ // IMP23368. Do not set tag to an EDGE shared by FACEs of a hyper-patch bool isInHyperPatch = false; + if ( e2ffmap.Contains( e )) // not there for a part of EDGE divided by enforced segments { std::set< int > faceTags, faceIDs; TopTools_ListIteratorOfListOfShape fIt( e2ffmap.FindFromKey( e )); @@ -2275,7 +2276,7 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh& aMesh, if ( !isInHyperPatch ) cad_edge_set_tag(edg, ic); - /* by default, an edge does not necessalry appear in the resulting mesh, + /* by default, an edge does not necessarily appear in the resulting mesh, unless the following property is set : */ cad_edge_set_property(edg, EDGE_PROPERTY_SOFT_REQUIRED); @@ -2299,9 +2300,9 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh& aMesh, for ( int iN = 0; iN < nbNodes; ++iN ) { const UVPtStruct& nData = nodeDataVec[ iN ]; - double t = nData.param; - real uv[2] = { nData.u, nData.v }; - SMESH_TNodeXYZ nXYZ( nData.node ); + double t = nData.param; + real uv[2] = { nData.u, nData.v }; + SMESH_TNodeXYZ nXYZ = nData.node; // cout << "\tt = " << t // << "\t uv = ( " << uv[0] << ","<< uv[1] << " ) " // << "\t u = " << nData.param @@ -2324,38 +2325,23 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh& aMesh, *****************************************************************************************/ int npts = 0; - int ip1, ip2, *ip; - gp_Pnt2d e0 = curves.back()->Value(tmin); - gp_Pnt ee0 = surfaces.back()->Value(e0.X(), e0.Y()); - Standard_Real d1=0,d2=0; - - int vertexKey = -1; - for (TopExp_Explorer ex_edge(e ,TopAbs_VERTEX); ex_edge.More(); ex_edge.Next()) { - TopoDS_Vertex v = TopoDS::Vertex(ex_edge.Current()); - ++npts; - if (npts == 1){ - ip = &ip1; - d1 = ee0.SquareDistance(BRep_Tool::Pnt(v)); - } else { - ip = &ip2; - d2 = ee0.SquareDistance(BRep_Tool::Pnt(v)); - } - *ip = pmap.FindIndex(v); - if(*ip <= 0) { - *ip = pmap.Add(v); - // SMESH_subMesh* sm = aMesh.GetSubMesh(v); - // if ( sm->IsMeshComputed() ) - // edgeSubmeshes.insert( sm->GetSubMeshDS() ); - } + int ip[2]; + double d[2]; + gp_Pnt2d uv0 = curves.back()->Value(tmin); + gp_Pnt p0 = surfaces.back()->Value( uv0.X(), uv0.Y() ); -// std::string aFileName = "fmap_vertex_"; -// aFileName.append(val_to_string(*ip)); -// aFileName.append(".brep"); -// BRepTools::Write(v,aFileName.c_str()); + for (TopExp_Explorer ex_edge(e ,TopAbs_VERTEX); ex_edge.More(); ex_edge.Next()) + { + const TopoDS_Vertex& v = TopoDS::Vertex(ex_edge.Current()); + ip[ npts ] = pmap.Add(v); + d [ npts ] = p0.SquareDistance(BRep_Tool::Pnt(v)); + ++npts; - if (HasSizeMapOnVertex){ - vertexKey = VerticesWithSizeMap.FindIndex(v); - if (VertexId2SizeMap.find(vertexKey)!=VertexId2SizeMap.end()){ + if (HasSizeMapOnVertex) + { + int vertexKey = VerticesWithSizeMap.FindIndex(v); + if (VertexId2SizeMap.find(vertexKey)!=VertexId2SizeMap.end()) + { theSizeMapStr = VertexId2SizeMap[vertexKey]; if (theSizeMapStr.find(bad_end) == (theSizeMapStr.size()-bad_end.size()-1)) continue; @@ -2371,23 +2357,65 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh& aMesh, PyGILState_Release(gstate); } } - } - if (npts != 2) { - // should not happen + } // loop on vertices + + if (npts != 2) { // should not happen MESSAGE("An edge does not have 2 extremities."); - } else { - if (d1 < d2) { - // This defines the curves extremity connectivity - cad_edge_set_extremities(edg, ip1, ip2); - /* set the tag (color) to the same value as the extremity id : */ - cad_edge_set_extremities_tag(edg, ip1, ip2); - } - else { - cad_edge_set_extremities(edg, ip2, ip1); - cad_edge_set_extremities_tag(edg, ip2, ip1); - } + continue; } + + if ( d[0] > d[1] ) + std::swap( ip[0], ip[1] ); + + // This defines the curves extremity connectivity + cad_edge_set_extremities (edg, ip[0], ip[1]); + /* set the tag (color) to the same value as the extremity id : */ + cad_edge_set_extremities_tag(edg, ip[0], ip[1]); + } // for edge + + // ============================== + // Add segments of enforced mesh + // ============================== + + if ( enforcedMesh.HasSegmentsOnFace( f )) + { + BLSURFPlugin_EnforcedMesh1D::Segmemnt seg; + while ( enforcedMesh.NextSegment( seg, pmap )) + { + curves.push_back( seg._pcurve ); + + cad_edge_t *edg = cad_edge_new( fce, seg._tag, seg._u[0], seg._u[1], + curv_fun,seg._pcurve.get()); + cad_edge_set_tag( edg, seg._tag ); + + cad_edge_set_property( edg, EDGE_PROPERTY_SOFT_REQUIRED ); + cad_edge_set_property( edg, EDGE_PROPERTY_INTERNAL ); + + cad_edge_set_extremities ( edg, seg._vTag[0], seg._vTag[1]); + cad_edge_set_extremities_tag( edg, seg._vTag[0], seg._vTag[1]); + + dcad_edge_discretization_t *dedge; + dcad_get_edge_discretization( dcad, edg, &dedge ); + dcad_edge_discretization_set_vertex_count( dedge, 2 ); + + dcad_edge_discretization_set_vertex_coordinates( dedge, 1, + seg._u [0], + &seg._uv[0].ChangeCoord(1), + seg._xyz[0].ChangeData() ); + dcad_edge_discretization_set_vertex_coordinates( dedge, 2, + seg._u [1], + &seg._uv[1].ChangeCoord(1), + seg._xyz[1].ChangeData() ); + + dcad_edge_discretization_set_vertex_tag( dedge, 1, seg._vTag[0] ); + dcad_edge_discretization_set_vertex_tag( dedge, 2, seg._vTag[1] ); + + dcad_edge_discretization_set_property(dedge, DISTENE_DCAD_PROPERTY_REQUIRED); + } + } + + } //for face /////////////////////// @@ -2502,10 +2530,6 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh& aMesh, // set_param(css, "max_size", val_to_string( minFaceSize * 5 ).c_str()); } - // TODO: be able to use a mesh in input. - // See imsh usage in Products/templates/mg-cadsurf_template_common.cpp - // => cadsurf_set_mesh - // Use the original dcad cadsurf_set_dcad(css, dcad); @@ -2591,7 +2615,8 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh& aMesh, std::string GMFFileName = BLSURFPlugin_Hypothesis::GetDefaultGMFFile(); if (_hypothesis) GMFFileName = _hypothesis->GetGMFFile(); - if (GMFFileName != "") { + if (GMFFileName != "") + { bool asciiFound = (GMFFileName.find(".mesh", GMFFileName.length()-5) != std::string::npos); bool binaryFound = (GMFFileName.find(".meshb",GMFFileName.length()-6) != std::string::npos); if (!asciiFound && !binaryFound) @@ -2604,9 +2629,9 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh& aMesh, integer *evedg, *evtri, *evquad, *tags_buff, type; real xyz[3]; - mesh_get_vertex_count(msh, &nv); - mesh_get_edge_count(msh, &ne); - mesh_get_triangle_count(msh, &nt); + mesh_get_vertex_count (msh, &nv); + mesh_get_edge_count (msh, &ne); + mesh_get_triangle_count (msh, &nt); mesh_get_quadrangle_count(msh, &nq); evedg = (integer *)mesh_calloc_generic_buffer(msh); @@ -2617,82 +2642,79 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh& aMesh, std::vector nodes(nv+1); std::vector tags(nv+1); + BLSURFPlugin_Hypothesis::TEnfVertexCoords projVertex; + /* enumerated vertices */ - for(int iv=1;iv<=nv;iv++) { + for ( int iv = 1; iv <= nv; iv++ ) + { mesh_get_vertex_coordinates(msh, iv, xyz); mesh_get_vertex_tag(msh, iv, &tag); // Issue 0020656. Use vertex coordinates nodes[iv] = NULL; - if ( tag > 0 && tag <= pmap.Extent() ) { - TopoDS_Vertex v = TopoDS::Vertex(pmap(tag)); - double tol = BRep_Tool::Tolerance( v ); - gp_Pnt p = BRep_Tool::Pnt( v ); - if ( p.IsEqual( gp_Pnt( xyz[0], xyz[1], xyz[2]), 1e3*tol)) - xyz[0] = p.X(), xyz[1] = p.Y(), xyz[2] = p.Z(); - else - tag = 0; // enforced or attracted vertex - nodes[iv] = SMESH_Algo::VertexNode( v, meshDS ); + if ( tag > 0 ) + { + if ( tag <= pmap.Extent() ) + { + TopoDS_Vertex v = TopoDS::Vertex(pmap(tag)); + double tol = BRep_Tool::Tolerance( v ); + gp_Pnt p = BRep_Tool::Pnt( v ); + if ( p.IsEqual( gp_Pnt( xyz[0], xyz[1], xyz[2]), 1e3*tol)) + xyz[0] = p.X(), xyz[1] = p.Y(), xyz[2] = p.Z(); + else + tag = 0; // enforced or attracted vertex + nodes[iv] = SMESH_Algo::VertexNode( v, meshDS ); + } + if ( !nodes[iv] && ( nodes[iv] = enforcedMesh.GetNodeByTag( tag, pmap ))) + { + continue; + } } if ( !nodes[iv] ) nodes[iv] = meshDS->AddNode(xyz[0], xyz[1], xyz[2]); // Create group of enforced vertices if requested - BLSURFPlugin_Hypothesis::TEnfVertexCoords projVertex; - projVertex.clear(); - projVertex.push_back((double)xyz[0]); - projVertex.push_back((double)xyz[1]); - projVertex.push_back((double)xyz[2]); - std::map< BLSURFPlugin_Hypothesis::TEnfVertexCoords, BLSURFPlugin_Hypothesis::TEnfVertexList >::const_iterator enfCoordsIt = EnfVertexCoords2EnfVertexList.find(projVertex); + projVertex.assign( xyz, xyz + 3 ); + auto enfCoordsIt = EnfVertexCoords2EnfVertexList.find( projVertex ); if (enfCoordsIt != EnfVertexCoords2EnfVertexList.end()) { - BLSURFPlugin_Hypothesis::TEnfVertexList::const_iterator enfListIt = enfCoordsIt->second.begin(); - BLSURFPlugin_Hypothesis::TEnfVertex *currentEnfVertex; - for (; enfListIt != enfCoordsIt->second.end(); ++enfListIt) { - currentEnfVertex = (*enfListIt); - if (currentEnfVertex->grpName != "") { - bool groupDone = false; - SMESH_Mesh::GroupIteratorPtr grIt = aMesh.GetGroups(); - while (grIt->more()) { + for ( BLSURFPlugin_Hypothesis::TEnfVertex *currentEnfVertex : enfCoordsIt->second ) + if (currentEnfVertex->grpName != "") + { + SMDS_MeshGroup* groupDS = nullptr; + for ( SMESH_Mesh::GroupIteratorPtr grIt = aMesh.GetGroups(); grIt->more() && !groupDS; ) + { SMESH_Group * group = grIt->next(); - if ( !group ) continue; - SMESHDS_GroupBase* groupDS = group->GetGroupDS(); - if ( !groupDS ) continue; - if ( groupDS->GetType()==SMDSAbs_Node && currentEnfVertex->grpName.compare(group->GetName())==0) { - SMESHDS_Group* aGroupDS = static_cast( groupDS ); - aGroupDS->SMDSGroup().Add(nodes[iv]); - // How can I inform the hypothesis ? - // _hypothesis->AddEnfVertexNodeID(currentEnfVertex->grpName,nodes[iv]->GetID()); - groupDone = true; - break; - } + SMESHDS_Group * grp = dynamic_cast< SMESHDS_Group* >( group->GetGroupDS() ); + if ( grp && + grp->GetType() == SMDSAbs_Node && + currentEnfVertex->grpName == group->GetName() ) + groupDS = &grp->SMDSGroup(); } - if (!groupDone) + if ( !groupDS ) { - SMESH_Group* aGroup = aMesh.AddGroup( SMDSAbs_Node, currentEnfVertex->grpName.c_str() ); - aGroup->SetName( currentEnfVertex->grpName.c_str() ); - SMESHDS_Group* aGroupDS = static_cast( aGroup->GetGroupDS() ); - aGroupDS->SMDSGroup().Add(nodes[iv]); - groupDone = true; + SMESH_Group * group = aMesh.AddGroup( SMDSAbs_Node, currentEnfVertex->grpName.c_str() ); + SMESHDS_Group * grp = static_cast< SMESHDS_Group* >( group->GetGroupDS() ); + groupDS = &grp->SMDSGroup(); } - if (!groupDone) - throw SALOME_Exception(LOCALIZED("An enforced vertex node was not added to a group")); + groupDS->Add( nodes[iv] ); } - else - MESSAGE("Group name is empty: '"<grpName<<"' => group is not created"); - } } // internal points are tagged to zero - if(tag > 0 && tag <= pmap.Extent() ){ + if ( tag > 0 && tag <= pmap.Extent() ) + { meshDS->SetNodeOnVertex(nodes[iv], TopoDS::Vertex(pmap(tag))); tags[iv] = false; - } else { + } + else + { tags[iv] = true; } } /* enumerate edges */ - for(int it=1;it<=ne;it++) { + for ( int it = 1; it <= ne; it++ ) + { SMDS_MeshEdge* edg; mesh_get_edge_vertices(msh, it, vtx); mesh_get_edge_extra_vertices(msh, it, &type, evedg); @@ -2703,14 +2725,21 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh& aMesh, // Get the initial tags corresponding to the output tag and redefine the tag as // the last of the two initial tags (else the output tag is out of emap and hasn't any meaning) mesh_get_composite_tag_definition(msh, tag, &nb_tag, tags_buff); - if(nb_tag > 1) - tag=tags_buff[nb_tag-1]; + if ( nb_tag > 1 ) + tag = tags_buff[ nb_tag-1 ]; if ( tag < 1 || tag > emap.Extent() ) { - std::cerr << "MG-CADSurf BUG:::: Edge tag " << tag - << " does not point to a CAD edge (nb edges " << emap.Extent() << ")" << std::endl; + if ( !enforcedMesh.IsSegmentTag( tag )) // it's a false INTERNAL EDGE of enforced mesh + { + std::cerr << "MG-CADSurf BUG:::: Edge tag " << tag + << " does not point to a CAD edge (nb edges " << emap.Extent() << ")" + << std::endl; + } continue; } + if ( meshDS->ShapeToIndex( emap( tag )) == 0 ) + tag = enforcedMesh.GetTagOfSplitEdge( tag ); + if (tags[vtx[0]]) { Set_NodeOnEdge(meshDS, nodes[vtx[0]], emap(tag)); tags[vtx[0]] = false; @@ -3207,31 +3236,27 @@ void BLSURFPlugin_BLSURF::Set_NodeOnEdge(SMESHDS_Mesh* meshDS, */ status_t curv_fun(real t, real *uv, real *dt, real *dtt, void *user_data) { - /* t is given. It contains the t (time) 1D parametric coordintaes - of the point PreCAD/MG-CADSurf is querying on the curve */ + /* t is given. It contains the 1D parametric coordintaes + of the point MG-CADSurf is querying on the curve */ - /* user_data identifies the edge PreCAD/MG-CADSurf is querying - * (see cad_edge_new later in this example) */ - const Geom2d_Curve*pargeo = (const Geom2d_Curve*) user_data; + /* user_data identifies the edge MG-CADSurf is querying */ + const Geom2d_Curve* pargeo = (const Geom2d_Curve*) user_data; - if (uv){ - /* MG-CADSurf is querying the function evaluation */ - gp_Pnt2d P; - P=pargeo->Value(t); + if (uv) { + /* MG-CADSurf is querying the function evaluation */ + gp_Pnt2d P = pargeo->Value(t); uv[0]=P.X(); uv[1]=P.Y(); } - if(dt) { - /* query for the first order derivatives */ - gp_Vec2d V1; - V1=pargeo->DN(t,1); + if (dt) { + /* query for the first order derivatives */ + gp_Vec2d V1 = pargeo->DN(t,1); dt[0]=V1.X(); dt[1]=V1.Y(); } - if(dtt){ + if (dtt) { /* query for the second order derivatives */ - gp_Vec2d V2; - V2=pargeo->DN(t,2); + gp_Vec2d V2 = pargeo->DN(t,2); dtt[0]=V2.X(); dtt[1]=V2.Y(); } diff --git a/src/BLSURFPlugin/BLSURFPlugin_BLSURF.hxx b/src/BLSURFPlugin/BLSURFPlugin_BLSURF.hxx index 167b761..936bdd3 100644 --- a/src/BLSURFPlugin/BLSURFPlugin_BLSURF.hxx +++ b/src/BLSURFPlugin/BLSURFPlugin_BLSURF.hxx @@ -132,6 +132,16 @@ public: typedef std::vector< TEdgePeriodicityIDs > TEdgesIDsPeriodicityVector; typedef std::vector< TVertexPeriodicityIDs > TVerticesIDsPeriodicityVector; + // Point projection on FACE + typedef struct { + gp_XY uv; + gp_XYZ xyz; + TopAbs_State state; + } projectionPoint; + + static projectionPoint getProjectionPoint(TopoDS_Face& theFace, + const gp_Pnt& thePoint, + const bool theAllowStateON=false); protected: @@ -162,7 +172,6 @@ private: private: PyObject * main_mod; PyObject * main_dict; - SMESH_MesherHelper* myHelper; volatile bool _compute_canceled; }; diff --git a/src/BLSURFPlugin/BLSURFPlugin_EnforcedMesh1D.cxx b/src/BLSURFPlugin/BLSURFPlugin_EnforcedMesh1D.cxx new file mode 100644 index 0000000..923bdfa --- /dev/null +++ b/src/BLSURFPlugin/BLSURFPlugin_EnforcedMesh1D.cxx @@ -0,0 +1,1332 @@ +// Copyright (C) 2007-2021 CEA/DEN, EDF R&D +// +// 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 +// +// File : BLSURFPlugin_EnforcedMesh1D.cxx +// Author : Edward AGAPOV (OCC) + +#include "BLSURFPlugin_EnforcedMesh1D.hxx" + +#include "BLSURFPlugin_BLSURF.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +// allow range iteration on NCollection_IndexedMap +template < class IMAP > +typename IMAP::const_iterator begin( const IMAP & m ) { return m.cbegin(); } +template < class IMAP > +typename IMAP::const_iterator end( const IMAP & m ) { return m.cend(); } + + +namespace +{ + //================================================================================ + /*! + * \brief Look for a node coincident with a given nodes among end nodes of a segment + * and among its internal nodes + * \param [in] p - the epoint + * \param [in] tol - 3D tolarace + * \param [in] segment - the segment + * \param [in] segInternalNodes - map of segment internal nodes + * \param [out] index - return index of found internal node; -1 if an end node is found + * \return const SMDS_MeshNode* - found node + */ + //================================================================================ + + const SMDS_MeshNode* findNode( const gp_Pnt& p, + const double tol, + const SMDS_MeshElement* segment, + BLSURFPlugin_EnforcedMesh1D::TNodesOnSeg & segInternalNodes, + int & index ) + { + + SMESH_NodeXYZ node0 = segment->GetNode(0); + if ( p.IsEqual( node0, tol )) + return index = -1, node0.Node(); + SMESH_NodeXYZ node1 = segment->GetNode(1); + if ( p.IsEqual( node1, tol )) + return index = -1, node1.Node(); + + auto seg2nodes = segInternalNodes.find( segment ); + if ( seg2nodes != segInternalNodes.end() ) + { + const std::vector< const SMDS_MeshNode* >& nodes = seg2nodes->second; + for ( size_t i = 0; i < nodes.size(); ++i ) + if ( p.IsEqual( SMESH_NodeXYZ( nodes[i] ), tol )) + { + index = (int) i; + return nodes[i]; + } + } + return nullptr; + } + + //================================================================================ + /*! + * \brief Orient segments to correspond to order of nodes in a branch + * \param [in] braSegs - segments of the branch + * \param [in] braNodes - nodes of the branch + * \param [in] nodeIndex - index of a node of the branch + * \param [inout] mesh - mesh holding the nodes and segments + * + * + */ + //================================================================================ + + void orientSegments( const std::vector< const SMDS_MeshElement* > & braSegs, + const std::vector< const SMDS_MeshNode* > & braNodes, + const size_t nodeIndex, + SMESH_Mesh* mesh ) + { + const SMDS_MeshElement* toReverse[2] = { nullptr, nullptr }; + + if ( nodeIndex > 0 && + braSegs[ nodeIndex - 1 ]->GetNode(1) != braNodes[ nodeIndex ]) + toReverse[ 0 ] = braSegs[ nodeIndex - 1 ]; + + if ( nodeIndex < braSegs.size() && + braSegs[ nodeIndex ]->GetNode(0) != braNodes[ nodeIndex ]) + toReverse[ bool( toReverse[0]) ] = braSegs[ nodeIndex ]; + + if ( !toReverse[0] ) + return; + + SMESH_MeshEditor editor( mesh ); + for ( int i = 0; i < 2; ++i ) + if ( toReverse[ i ]) + editor.Reorient( toReverse[ i ]); + } + +} // namespace + +//================================================================================ +/*! + * \brief Create enforced mesh segments in a mesh + * \param [in] helper - contains the mesh and the shape to compute + * \param [in] hyp - hypothesis containing data of enforced meshes + */ +//================================================================================ + +BLSURFPlugin_EnforcedMesh1D::BLSURFPlugin_EnforcedMesh1D( SMESH_MesherHelper& helper, + const BLSURFPlugin_Hypothesis* hyp ) + : _mesh ( helper.GetMesh() ), + _shape( helper.GetSubShape() ), + _helper( *_mesh ), + _isQuadratic( helper.GetIsQuadratic() ) +{ + if ( !hyp || !_mesh || hyp->GetEnforcedMeshes().empty() ) + return; + + _tol = 2 * BRep_Tool::MaxTolerance( _shape, TopAbs_VERTEX ); + _segTag = 1000 + helper.Count( _shape, TopAbs_EDGE, /*ignoreSame=*/false ); + _segTag0 = _segTag; + _nodeTag0 = 1000 + helper.Count( _shape, TopAbs_VERTEX, /*ignoreSame=*/false ); + + for ( const BLSURFPlugin_Hypothesis::EnforcedMesh& enfMesh : hyp->GetEnforcedMeshes() ) + { + copyEnforcedMesh( enfMesh, hyp, _shape ); + } + + for ( const SMDS_MeshElement* segment : _segmentsOnSeveralShapes ) + { + splitSegmentOnSeveralShapes( segment ); + } + + for ( const TopoDS_Shape & face : _faces ) + { + splitSelfIntersectingSegments( face ); + } + + for ( TEdge2Nodes::Iterator e2nn( _nodesOnEdge ); e2nn.More(); e2nn.Next() ) + { + splitEdgeByNodes( e2nn.Key(), e2nn.Value() ); + } +} + +//================================================================================ +/*! + * \brief Convert enforced segments to quadratic + */ +//================================================================================ + +BLSURFPlugin_EnforcedMesh1D::~BLSURFPlugin_EnforcedMesh1D() +{ + if ( !_isQuadratic ) + return; + + _helper.SetIsQuadratic( true ); + + SMESHDS_Mesh* meshDS = _mesh->GetMeshDS(); + std::vector nodes(2); + std::vector trias; + + SMDS_MeshGroup* group = nullptr; + if ( !_name2Group.empty() ) + group = _name2Group.begin()->second; + + for ( const TopoDS_Shape& f : _faces ) + if ( HasSegmentsOnFace( TopoDS::Face( f ))) + while ( _segIterator->more() ) + { + const SMDS_MeshElement* segment = _segIterator->next(); + if ( segment->GetType() != SMDSAbs_Edge ) + break; + + nodes[0] = segment->GetNode(0); + nodes[1] = segment->GetNode(1); + if ( meshDS->GetElementsByNodes( nodes, trias, SMDSAbs_Face )) + { + if ( !group || !group->Contains( segment )) + { + SMDS_MeshGroup* otherGroup = nullptr; + if ( _name2Group.size() > bool( group )) + for ( auto & n2g : _name2Group ) + if ( n2g.second != group && n2g.second->Contains( segment )) + { + otherGroup = n2g.second; + break; + } + group = otherGroup; + } + + _helper.AddTLinks( static_cast< const SMDS_MeshFace* >( trias[0] )); + + meshDS->RemoveFreeElement( segment, meshDS->MeshElements( f ), /*fromGroup=*/false ); + + SMDS_MeshElement* quadSegment = _helper.AddEdge( nodes[0], nodes[1], + /*id=*/0, /*force3d=*/false ); + if ( group && segment != quadSegment ) + { + group->Remove( segment ); + group->Add( quadSegment ); + } + } + } + return; +} + +//================================================================================ +/*! + * \brief Return EDGEs resulted from division of FACE boundary by enforced segments + * \param [in] edge - possibly divided EDGE + * \param [out] splits - split EDGEs + * \return bool - true if the EDGE is split + */ +//================================================================================ + +bool BLSURFPlugin_EnforcedMesh1D::GetSplitsOfEdge( const TopoDS_Edge& edge, + std::vector< TopoDS_Edge > & splits, + TopTools_IndexedMapOfShape & edgeTags ) +{ + std::vector< TopoDS_Edge > * splitsInMap = _edgeSplitsOfEdge.ChangeSeek( edge ); + if ( !splitsInMap ) + return false; + + splits.insert( splits.end(), splitsInMap->begin(), splitsInMap->end() ); + + int eTag = edgeTags.Add( edge ); + + size_t index = splits.size() - 1; + for ( size_t i = 0; i < splitsInMap->size(); ++i, --index ) + { + int splitTag = edgeTags.Add( splits[ index ]); + _splitTags2EdgeTag[ splitTag ] = eTag; + + if ( edge.Orientation() == TopAbs_REVERSED ) + splits[ index ].Reverse(); + } + + return true; +} + + +//================================================================================ +/*! + * \brief Add 1D elements to the mesh + */ +//================================================================================ + +void BLSURFPlugin_EnforcedMesh1D:: + +copyEnforcedMesh( const BLSURFPlugin_Hypothesis::EnforcedMesh& theEnfMesh, + const BLSURFPlugin_Hypothesis* theHyp, + const TopoDS_Shape& theShape) +{ + SMESH_Mesh* mesh1D; + SMDS_ElemIteratorPtr segIt = theHyp->GetEnforcedSegments( theEnfMesh, mesh1D ); + if ( !segIt->more() ) + return; + + // setup predicates to detect nodes on FACE boundary + setupPredicates( theShape ); + + SMDS_MeshGroup* group = getGroup( theEnfMesh._groupName ); + SMESHDS_Mesh* meshDS = _helper.GetMeshDS(); + + // get ordered nodes and segments of theEnfMesh + SMESH_MeshAlgos::TElemGroupVector edgeBranches; + SMESH_MeshAlgos::TNodeGroupVector nodeBranches; + SMESH_MeshAlgos::Get1DBranches( segIt, edgeBranches, nodeBranches ); + + + // Copy nodes and segments from an enforced mesh to my mesh + + TopoDS_Shape vertex, edge; + + // first treat ends of branches that can be shared by branches + for ( size_t iB = 0; iB < nodeBranches.size(); ++iB ) + { + std::vector< const SMDS_MeshNode* > & braNodes = nodeBranches[ iB ]; + std::vector< const SMDS_MeshElement* > & braSegs = edgeBranches[ iB ]; + + for ( int isLast = 0; isLast < 2; ++isLast ) + { + const SMDS_MeshNode* enfNode = isLast ? braNodes.back() : braNodes[0]; + if ( meshDS->Contains( enfNode )) + continue; // already in my mesh + + const SMDS_MeshNode* newNode = copyEnforcedNode( enfNode ); + if ( !newNode ) + orientSegments( braSegs, braNodes, isLast ? 0 : braNodes.size() - 1, mesh1D ); + + // replace enfNode at branch ends by newNode + SMESH_NodeXYZ enfPnt( newNode ? newNode : enfNode ); + for ( std::vector< const SMDS_MeshNode* > & braNodes : nodeBranches ) + { + for ( int isLast = 0; isLast < 2; ++isLast ) + { + const SMDS_MeshNode* & endNode = isLast ? braNodes.back() : braNodes[0]; + if ( endNode == enfNode || enfPnt.SquareDistance( endNode ) < _tol*_tol ) + endNode = newNode; + } + } + continue; + } // loop on branch ends + } // loop on nodeBranches + + // copy nodes and segments + + for ( size_t iB = 0; iB < nodeBranches.size(); ++iB ) + { + std::vector< const SMDS_MeshNode* > & braNodes = nodeBranches[ iB ]; + std::vector< const SMDS_MeshElement* > & braSegs = edgeBranches[ iB ]; + + // copy nodes of the branch + for ( size_t i = 0; i < braNodes.size(); ++i ) + { + const SMDS_MeshNode* & enfNode = braNodes[ i ]; + const SMDS_MeshNode* newNode = copyEnforcedNode( enfNode ); + + if ( !newNode ) // orient segments to be able to get enforced not projected node + orientSegments( braSegs, braNodes, i, mesh1D ); + + enfNode = newNode; + } + + // copy segments of the branch + for ( size_t i = 0; i < braSegs.size(); ++i ) + { + //braSegs[ i ] = nullptr; + + const SMDS_MeshNode* node0 = braNodes[ i ]; + const SMDS_MeshNode* node1 = braNodes[ i + 1 ]; + if ( !node0 && !node1 ) + continue; + + TopoDS_Shape shape0 = _helper.GetSubShapeByNode( node0, meshDS ); + TopoDS_Shape shape1 = _helper.GetSubShapeByNode( node1, meshDS ); + if ( shape0.IsNull() && shape1.IsNull() ) + continue; + + if ( !node0 && shape1.ShapeType() != TopAbs_FACE ) + continue; + if ( !node1 && shape0.ShapeType() != TopAbs_FACE ) + continue; + + if ( !node0 || !node1 ) // create missing node at location of enforced node projected nowhere + { + SMESH_NodeXYZ pn = braSegs[i]->GetNode( !node1 ); + ( node0 ? node1 : node0 ) = _helper.AddNode( pn->X(), pn->Y(), pn->Z() ); + } + + SMDS_MeshEdge* newSeg = _helper.AddEdge( node0, node1 ); + if ( group ) + group->Add( newSeg ); + braSegs[ i ] = newSeg; + + // check if the both nodes are on the same FACE + TopoDS_Shape face = shape0; + if ( !shape0.IsSame( shape1 ) && !shape0.IsNull() && !shape1.IsNull() ) + { + if ( shape0.ShapeType() == TopAbs_FACE && + _helper.IsSubShape( shape1, shape0 )) + { + face = shape0; + } + else if ( shape1.ShapeType() == TopAbs_FACE && + _helper.IsSubShape( shape0, shape1 )) + { + face = shape1; + } + else // try to find a FACE by projecting a segment middle point + { + face.Nullify(); + gp_Pnt middlePnt = 0.5 * ( SMESH_NodeXYZ( node0 ) + SMESH_NodeXYZ( node1 )); + //BLSURFPlugin_BLSURF::projectionPoint projPnt = + BLSURFPlugin_BLSURF::getProjectionPoint( TopoDS::Face( face ), middlePnt ); + + if ( !face.IsNull() && + ( !_helper.IsSubShape( shape0, face ) || + !_helper.IsSubShape( shape1, face ) )) + face.Nullify(); + } + } + if ( !face.IsNull() && face.ShapeType() == TopAbs_FACE ) + { + meshDS->SetMeshElementOnShape( newSeg, face ); + _faces.Add( face ); + } + + if ( face.IsNull() || shape0.IsNull() || shape1.IsNull() ) + { + _segmentsOnSeveralShapes.push_back( newSeg ); + } + + } // loop on branch segments + continue; + } // loop on branches + + return; +} + +//================================================================================ +/*! + * \brief Create a copy of a node of enforced mesh in my mesh + * \param [in] enfNode - enforced node + * \return const SMDS_MeshNode* - a node in my mesh + */ +//================================================================================ + +const SMDS_MeshNode* BLSURFPlugin_EnforcedMesh1D::copyEnforcedNode( const SMDS_MeshNode* enfNode ) +{ + SMESHDS_Mesh * meshDS = _helper.GetMeshDS(); + + if ( !enfNode || meshDS->Contains( enfNode )) + return enfNode; // already in my mesh + + SMESH_NodeXYZ enfPnt = enfNode; + + const SMDS_MeshNode* newNode = nullptr; + + // check if enfNode is on VERTEX + TopoDS_Vertex vertex; + if ( _onVertexPredicate->IsSatisfy( enfNode, &vertex )) + { + _mesh->GetSubMesh( vertex )->ComputeStateEngine( SMESH_subMesh::COMPUTE ); + newNode = SMESH_Algo::VertexNode( vertex, meshDS ); + } + + // check if enfNode is on EDGE + bool setNodeOnEdge = false; + TopoDS_Edge edge; + if ( !newNode ) + { + setNodeOnEdge = _onEdgePredicate->IsSatisfy( enfNode, &edge ); + if ( setNodeOnEdge ) + { + newNode = findNodeOnEdge( enfPnt, edge ); + setNodeOnEdge = !newNode; + } + } + + // create a new node and set it on FACE + if ( !newNode ) + { + TopoDS_Face face; + BLSURFPlugin_BLSURF::projectionPoint projPnt = + BLSURFPlugin_BLSURF::getProjectionPoint( face, enfPnt, /*allowStateON=*/true ); + if ( face.IsNull() ) return newNode; + + if ( projPnt.state == TopAbs_ON ) + { + SMDS_MeshNode* projNode = const_cast< SMDS_MeshNode* >( enfNode ); + projNode->setXYZ( projPnt.xyz.X(), projPnt.xyz.Y(), projPnt.xyz.Z() ); + vertex.Nullify(); + edge.Nullify(); + if ( _onVertexPredicate->IsSatisfy( projNode, &vertex )) + { + _mesh->GetSubMesh( vertex )->ComputeStateEngine( SMESH_subMesh::COMPUTE ); + newNode = SMESH_Algo::VertexNode( vertex, meshDS ); + } + else if (( setNodeOnEdge = _onEdgePredicate->IsSatisfy( projNode, &edge ))) + { + newNode = findNodeOnEdge( projPnt.xyz, edge ); + setNodeOnEdge = !newNode; + } + projNode->setXYZ( enfPnt.X(), enfPnt.Y(), enfPnt.Z() ); + } + + if ( !newNode ) + newNode = meshDS->AddNode( projPnt.xyz.X(), projPnt.xyz.Y(), projPnt.xyz.Z() ); + + if ( vertex.IsNull() && edge.IsNull() ) + meshDS->SetNodeOnFace( newNode, face, projPnt.uv.X(), projPnt.uv.Y() ); + } + + // set the new node on EDGE + if ( newNode && setNodeOnEdge ) + { + addNodeOnEdge( newNode, edge ); + } + + return newNode; +} + +//================================================================================ +/*! + * \brief Split a segment whose nodes are on different FACEs into smaller parts + * lying each on one FACE + */ +//================================================================================ + +void BLSURFPlugin_EnforcedMesh1D::splitSegmentOnSeveralShapes( const SMDS_MeshElement* segment ) +{ + const SMDS_MeshNode* node0 = segment->GetNode(0); + const SMDS_MeshNode* node1 = segment->GetNode(1); + SMESHDS_Mesh * meshDS = _helper.GetMeshDS(); + + TopoDS_Shape shape0 = _helper.GetSubShapeByNode( node0, meshDS ); + TopoDS_Shape shape1 = _helper.GetSubShapeByNode( node1, meshDS ); + + if ( shape0.IsNull() ) + { + std::swap( node0, node1 ); + shape0 = shape1; + shape1.Nullify(); + } + + gp_XYZ xyz0 = SMESH_NodeXYZ( node0 ); + gp_XYZ xyz1 = SMESH_NodeXYZ( node1 ); + gp_XYZ segDir = ( xyz1 - xyz0 ).Normalized(); + + //std::map< double, const SMDS_MeshNode* > mediumNodes; // nodes splitting the segment + + while ( !shape0.IsSame( shape1 )) // move along the segment till shape1 + { + if ( shape0.ShapeType() == TopAbs_FACE ) // make a node on an EDGE of the FACE + { // ---------------------------------- + TopoDS_Edge edge; + double paramOnE; + gp_Pnt edgeIntPnt = getEdgeIntersection( shape0, xyz0, xyz1, edge, paramOnE ); + if ( edge.IsNull() ) + break; + + // check if edgeIntPnt in on VERTEX + TopoDS_Vertex vertex; + for ( int iV = 0; iV < 2 && vertex.IsNull(); ++iV ) + { + TopoDS_Vertex v = _helper.IthVertex( iV, edge ); + if ( edgeIntPnt.SquareDistance( BRep_Tool::Pnt( v )) < _tol *_tol ) + vertex = v; + } + + // make a node on the EDGE + const SMDS_MeshNode* nodeOnEdge = nullptr; + if ( vertex.IsNull() ) + { + nodeOnEdge = findNodeOnEdge( edgeIntPnt, edge ); + if ( !nodeOnEdge ) + { + if ( shape1.IsNull() && node1 ) + { + nodeOnEdge = node1; + node1 = nullptr; + meshDS->MoveNode( nodeOnEdge, edgeIntPnt.X(), edgeIntPnt.Y(), edgeIntPnt.Z() ); + } + else + { + nodeOnEdge = _helper.AddNode( edgeIntPnt.X(), edgeIntPnt.Y(), edgeIntPnt.Z() ); + } + addNodeOnEdge( nodeOnEdge, edge, paramOnE ); + } + } + else + { + _mesh->GetSubMesh( vertex )->ComputeStateEngine( SMESH_subMesh::COMPUTE ); + nodeOnEdge = SMESH_Algo::VertexNode( vertex, meshDS ); + } + + // create a sub-segment + SMDS_MeshElement* newSeg = _helper.AddEdge( node0, nodeOnEdge ); + meshDS->SetMeshElementOnShape( newSeg, shape0 ); + + SMESH_MeshEditor::AddToSameGroups( newSeg, segment, meshDS ); + + node0 = nodeOnEdge; + xyz0 = SMESH_NodeXYZ( node0 ); + if ( vertex.IsNull() ) + shape0 = edge; + else + shape0 = vertex; + } + + else // shape0 is EDGE or VERTEX; look for the next FACE + { // ------------------------------------------------ + + if ( !shape1.IsNull() && + shape1.ShapeType() == TopAbs_FACE && + _helper.IsSubShape( shape0, shape1 )) // shape0 belongs to FACE shape1 + { + SMDS_MeshElement* newSeg = _helper.AddEdge( node0, node1 ); + SMESH_MeshEditor::AddToSameGroups( newSeg, segment, meshDS ); + meshDS->SetMeshElementOnShape( newSeg, shape1 ); + break; + } + // FACE search + TopoDS_Face face; + double shift = 10 * _tol; + for ( int nbAttemp = 0; face.IsNull() && nbAttemp < 10; ++nbAttemp ) + { + xyz0 += segDir * shift; + shift *= 2; + BLSURFPlugin_BLSURF::getProjectionPoint( face, xyz0 ); + } + if ( !face.IsNull() ) + { + if ( _helper.IsSubShape( shape0, face )) + _faces.Add( face ); + else + break; + shape0 = face; + } + else + { + break; + } + } + continue; + } //while ( !shape0.IsSame( shape1 )) + + meshDS->RemoveFreeElement( segment, /*submesh=*/nullptr ); +} + +//================================================================================ +/*! + * \brief Find intersection of FACE EDGEs and a segment + * \param [in] theFace - the FACE + * \param [in] thePnt0 - first end of the segment + * \param [in] thePnt1 - last end of the segment + * \param [out] theFounfEdge - return the intersected EDGE + * \param [out] theParamOnEdge - return parameter of intersection point on EDGE + * \return gp_XYZ - point on an EDGE closest to the segment + */ +//================================================================================ + +gp_Pnt BLSURFPlugin_EnforcedMesh1D::getEdgeIntersection( const TopoDS_Shape& theFaceOrEdge, + const gp_XYZ& thePnt0, + const gp_XYZ& thePnt1, + TopoDS_Edge & theFounfEdge, + double & theParamOnEdge) +{ + const double segLen = ( thePnt1 - thePnt0 ).Modulus(); + const double maxSegDist2 = segLen * segLen * 0.5 * 0.5; + + Handle(Geom_Line) segLine = new Geom_Line( thePnt0, thePnt1 - thePnt0 ); + GeomAdaptor_Curve segLineAdpt( segLine, 0, segLen ); + + TopTools_MapOfShape edges; + double minParamOnSeg = segLen; + gp_Pnt foundPnt; + for ( TopExp_Explorer edgeExp( theFaceOrEdge, TopAbs_EDGE ); edgeExp.More(); edgeExp.Next() ) + { + const TopoDS_Edge& edge = TopoDS::Edge( edgeExp.Current() ); + if ( !edges.Add( edge )) + continue; + + Extrema_ExtCC extrema( segLineAdpt, BRepAdaptor_Curve( edge ), _tol, _tol ); + + if ( extrema.IsDone() && !extrema.IsParallel() ) + for ( int i = 1, nb = extrema.NbExt(); i <= nb; ++i ) + if ( extrema.SquareDistance( i ) < maxSegDist2 ) + { + Extrema_POnCurv pOnSeg, pOnEdge; + extrema.Points( i, pOnSeg, pOnEdge ); + double paramOnSeg = pOnSeg.Parameter(); + if ( 0 < paramOnSeg && paramOnSeg < minParamOnSeg ) + { + minParamOnSeg = paramOnSeg; + foundPnt = pOnEdge.Value(); + theFounfEdge = edge; + theParamOnEdge = pOnEdge.Parameter(); + } + } + } + return foundPnt; +} + +//================================================================================ +/*! + * \brief Split self-intersecting segments on a given FACE + */ +//================================================================================ + +void BLSURFPlugin_EnforcedMesh1D::splitSelfIntersectingSegments( const TopoDS_Shape & theFace ) +{ + const TopoDS_Face& face = TopoDS::Face( theFace ); + + SMESHDS_Mesh* meshDS = _helper.GetMeshDS(); + SMESHDS_SubMesh* sm = meshDS->MeshElements( face ); + if ( !sm || sm->NbElements() <= 1 ) + return; + + // get ordered nodes and segments on the face + SMESH_MeshAlgos::TElemGroupVector edgeBranches; + SMESH_MeshAlgos::TNodeGroupVector nodeBranches; + SMESH_MeshAlgos::Get1DBranches( sm->GetElements(), edgeBranches, nodeBranches ); + + // create element searcher + SMESH_ElementSearcher* elemSearcher; + SMESHUtils::Deleter< SMESH_ElementSearcher > elSearchdeleter; + std::vector< const SMDS_MeshElement* > foundElems; + { + std::vector< SMDS_ElemIteratorPtr > elemItVec; + for ( std::vector< const SMDS_MeshElement* > & braSegs : edgeBranches ) + { + SMDS_ElemIteratorPtr segIt = + boost::make_shared< SMDS_ElementVectorIterator >( braSegs.begin(), braSegs.end() ); + elemItVec.push_back( segIt ); + } + typedef SMDS_IteratorOnIterators< const SMDS_MeshElement*, + std::vector< SMDS_ElemIteratorPtr > > TVecIterator; + SMDS_ElemIteratorPtr segIt = boost::make_shared< TVecIterator >( elemItVec ); + + elemSearcher = SMESH_MeshAlgos::GetElementSearcher( *meshDS, segIt, _tol ); + elSearchdeleter._obj = elemSearcher; + + // force usage of iterators before they die + elemSearcher->FindElementsByPoint( gp_Pnt( 0,0,1e+20), SMDSAbs_Edge, foundElems ); + } + + + // Find intersecting segments + + std::map< const SMDS_MeshElement* , std::vector< const SMDS_MeshNode* > > segInternalNodes; + SMESH_MeshEditor::TListOfListOfNodes nodeGroupsToMerge; + + for ( std::vector< const SMDS_MeshElement* > & braSegs : edgeBranches ) + { + braSegs.push_back( braSegs.back() ); + const SMDS_MeshElement* prevSeg = nullptr; + + for ( size_t i = 0, nb = braSegs.size() - 1; i < nb; ++i ) + { + const SMDS_MeshElement* seg = braSegs[ i ]; + const SMDS_MeshElement* nextSeg = braSegs[ i + 1 ]; + const SMDS_MeshNode* node0 = seg->GetNode(0); + const SMDS_MeshNode* node1 = seg->GetNode(1); + + gp_XYZ xyz0 = SMESH_NodeXYZ( node0 ); + gp_XYZ xyz1 = SMESH_NodeXYZ( node1 ); + gp_XYZ middlePnt = 0.5 * ( SMESH_NodeXYZ( node0 ) + SMESH_NodeXYZ( node1 )); + double segLen = ( xyz0 - xyz1 ).Modulus(); + + foundElems.clear(); + elemSearcher->GetElementsInSphere( middlePnt, 0.5 * segLen + _tol, SMDSAbs_Edge, foundElems ); + + for ( const SMDS_MeshElement* closeSeg : foundElems ) + { + if ( closeSeg == prevSeg || + closeSeg >= seg || + closeSeg == nextSeg ) + continue; + + gp_Pnt intPnt; + gp_Pnt2d uv; + if ( intersectSegments( seg, closeSeg, face, intPnt, uv )) + { + int i0, i1; + const SMDS_MeshNode* intNode0 = findNode( intPnt, _tol, seg, segInternalNodes, i0 ); + const SMDS_MeshNode* intNode1 = findNode( intPnt, _tol, closeSeg, segInternalNodes, i1 ); + if ( !intNode0 && intNode1 ) + { + segInternalNodes[ seg ].push_back( intNode1 ); + } + else if ( !intNode1 && intNode0 ) + { + segInternalNodes[ closeSeg ].push_back( intNode0 ); + } + else if ( intNode1 && intNode0 ) + { + if ( intNode1 == intNode0 ) + continue; + if ( i0 < 0 && i1 < 0 ) + { + nodeGroupsToMerge.push_back // merge end nodes + ( std::list< const SMDS_MeshNode* >({ intNode0, intNode1 })); + } + else if ( i0 < 0 ) + { + segInternalNodes[ closeSeg ][ i1 ] = intNode0; + } + else if ( i1 < 0 ) + { + segInternalNodes[ seg ][ i0 ] = intNode1; + } + else // two internal nodes coincide + { + segInternalNodes[ seg ][ i0 ] = intNode1; + nodeGroupsToMerge.push_back + ( std::list< const SMDS_MeshNode* >({ intNode1, intNode0 })); + } + } + else // ( !intNode1 && !intNode0 ) + { + intNode0 = _helper.AddNode( intPnt.X(), intPnt.Y(), intPnt.Z() ); + meshDS->SetNodeOnFace( intNode0, face, uv.X(), uv.Y() ); + segInternalNodes[ seg ].push_back( intNode0 ); + segInternalNodes[ closeSeg ].push_back( intNode0 ); + } + } + } + + prevSeg = seg; + + } // loop on segments of a branch + } // loop on branches + + + findIntersectionWithSeamEdge( face, segInternalNodes ); // on periodic FACE + + + // Split segments + + for ( auto& seg2nodes : segInternalNodes ) + { + const SMDS_MeshElement* seg = seg2nodes.first; + std::vector< const SMDS_MeshNode* > & nodes = seg2nodes.second; + if ( nodes.empty() ) continue; + + const SMDS_MeshNode* n0 = seg->GetNode( 0 ); + const SMDS_MeshNode* n1 = seg->GetNode( 1 ); + nodes.push_back( n1 ); + + // sort nodes on the segment + gp_Pnt p0 = SMESH_NodeXYZ( n0 ); + std::map< double, const SMDS_MeshNode* > sortedNodes; + for ( SMESH_NodeXYZ pn : nodes ) + sortedNodes.insert({ p0.SquareDistance( pn ), pn.Node() }); + + // make new segments + for ( auto & d2n : sortedNodes ) + { + n1 = d2n.second; + SMDS_MeshElement* newSeg = _helper.AddEdge( n0, n1 ); + n0 = n1; + meshDS->SetMeshElementOnShape( newSeg, face ); + SMESH_MeshEditor::AddToSameGroups( newSeg, seg, meshDS ); + } + meshDS->RemoveFreeElement( seg, /*submesh=*/nullptr ); + } + + + // merge equal nodes + SMESH_MeshEditor( _mesh ).MergeNodes( nodeGroupsToMerge ); +} + +//================================================================================ +/*! + * \brief Find intersections of segments with a seam EDGE on a periodic FACE + */ +//================================================================================ + +void BLSURFPlugin_EnforcedMesh1D::findIntersectionWithSeamEdge( const TopoDS_Face & face, + TNodesOnSeg & segInternalNodes ) +{ + _helper.SetSubShape( face ); + if ( !_helper.HasSeam() ) + return; + + SMESHDS_Mesh* meshDS = _helper.GetMeshDS(); + SMESHDS_SubMesh* sm = meshDS->MeshElements( face ); + if ( !sm || sm->NbElements() == 0 ) + return; + + TopTools_MapOfShape treatedEdges; + for ( TopExp_Explorer edgeExp( face, TopAbs_EDGE ); edgeExp.More(); edgeExp.Next() ) + { + const TopoDS_Edge& edge = TopoDS::Edge( edgeExp.Current() ); + if ( !_helper.IsSeamShape( edge ) || !treatedEdges.Add( edge )) + continue; + + for ( SMDS_ElemIteratorPtr setIt = sm->GetElements(); setIt->more(); ) + { + const SMDS_MeshElement* segment = setIt->next(); + const SMESH_NodeXYZ pn0 = segment->GetNode( 0 ); + const SMESH_NodeXYZ pn1 = segment->GetNode( 1 ); + + gp_XY uv0 = _helper.GetNodeUV( face, pn0.Node() ); + gp_XY uv1 = _helper.GetNodeUV( face, pn1.Node() ); + + for ( int iCoo = 1; iCoo <= 2; ++iCoo ) + if ( iCoo & _helper.GetPeriodicIndex() ) + { + double distParam = Abs( uv0.Coord( iCoo ) - uv1.Coord( iCoo )); + if ( distParam > 0.5 * _helper.GetPeriod( iCoo )) + { + double paramOnE; TopoDS_Edge edge2; + gp_Pnt edgeIntPnt = getEdgeIntersection( edge, pn0, pn1, edge2, paramOnE ); + if ( edge2.IsNull() ) + continue; + + const SMDS_MeshNode* nodeOnSeam = findNodeOnEdge( edgeIntPnt, edge ); + bool isOnEdge = nodeOnSeam; + + int indexOnSegment = 3; + if ( !nodeOnSeam ) + nodeOnSeam = findNode( edgeIntPnt, _tol, segment, segInternalNodes, indexOnSegment ); + + if ( !nodeOnSeam ) + { + nodeOnSeam = _helper.AddNode( edgeIntPnt.X(), edgeIntPnt.Y(), edgeIntPnt.Z() ); + } + + if ( !isOnEdge ) + { + addNodeOnEdge( nodeOnSeam, edge, paramOnE ); + } + if ( indexOnSegment == 3 ) + segInternalNodes[ segment ].push_back( nodeOnSeam ); + } + } + } + } +} + +//================================================================================ +/*! + * \brief Intersect two segments + * \param [in] seg1 - segment 1 + * \param [in] seg2 - segment 2 + * \param [in] face - the FACE on which segments lie + * \param [out] intPnt - intersection point + * \param [out] intUV - UV of intersection point on the FACE + * \return bool - true if intersection found + */ +//================================================================================ + +bool BLSURFPlugin_EnforcedMesh1D::intersectSegments( const SMDS_MeshElement* seg1, + const SMDS_MeshElement* seg2, + const TopoDS_Face& face, + gp_Pnt & intPnt, + gp_Pnt2d & intUV ) const +{ + SMESH_NodeXYZ n10 = seg1->GetNode(0); + SMESH_NodeXYZ n11 = seg1->GetNode(1); + SMESH_NodeXYZ n20 = seg2->GetNode(0); + SMESH_NodeXYZ n21 = seg2->GetNode(1); + if ( n10 == n20 || n10 == n21 || n11 == n20 || n10 == n21 ) + return false; + + gp_Lin lin1( n10, n11 - n10 ); + gp_Lin lin2( n20, n21 - n20 ); + + Extrema_ExtElC extrema( lin1, lin2, Precision::Angular() ); + + if ( !extrema.IsDone() || extrema.IsParallel() ) + return false; + + Extrema_POnCurv poc1, poc2; + extrema.Points( 1, poc1, poc2 ); + + double len1 = lin1.Direction().XYZ() * ( n11 - n10 ); + double len2 = lin2.Direction().XYZ() * ( n21 - n20 ); + double u1 = poc1.Parameter(); + double u2 = poc2.Parameter(); + + if ( u1 < -_tol || u1 > len1 + _tol ) + return false; + if ( u2 < -_tol || u2 > len2 + _tol ) + return false; + + intPnt = 0.5 * ( poc1.Value().XYZ() + poc2.Value().XYZ() ); + + // compute approximate UV + + u1 /= len1; + u2 /= len2; + + gp_XY uv10 = _helper.GetNodeUV( face, n10.Node(), n11.Node() ); + gp_XY uv11 = _helper.GetNodeUV( face, n11.Node(), n10.Node() ); + gp_XY uv1 = uv10 * ( 1 - u1 ) + uv11 * u1; + + gp_XY uv20 = _helper.GetNodeUV( face, n20.Node(), n21.Node() ); + gp_XY uv21 = _helper.GetNodeUV( face, n21.Node(), n20.Node() ); + gp_XY uv2 = uv20 * ( 1 - u2 ) + uv21 * u2; + + intUV = 0.5 * ( uv1 + uv2 ); + + // compute precise UV and XYZ by projecting intPnt to the FACE + + Handle(ShapeAnalysis_Surface) surface = _helper.GetSurface( face ); + intUV = surface->NextValueOfUV( intUV, intPnt, _tol ); + if ( surface->Gap() > Min( len1, len2 )) + intUV = surface->ValueOfUV( intPnt, _tol ); + + intPnt = surface->Value( intUV ); + + return true; +} + +//================================================================================ +/*! + * \brief Setup predicates to detect nodes on FACE boundary + * \param [in] shape - shape containing FACEs to mesh + */ +//================================================================================ + +void BLSURFPlugin_EnforcedMesh1D::setupPredicates( const TopoDS_Shape& theShape ) +{ + if ( _onVertexPredicate ) + return; + + _onVertexPredicate.reset( new TPredicate() ); + _onVertexPredicate->SetTolerance( _tol ); + _onVertexPredicate->SetMesh( _helper.GetMeshDS() ); + { + TopTools_IndexedMapOfShape vertices; + TopExp::MapShapes( theShape, TopAbs_VERTEX, vertices ); + TopoDS_Compound vCompound; + BRep_Builder builder; + builder.MakeCompound( vCompound ); + for ( const TopoDS_Shape& v : vertices ) + builder.Add( vCompound, v ); + + _onVertexPredicate->SetShape( vCompound, SMDSAbs_Node ); + } + + + _onEdgePredicate.reset( new TPredicate() ); + _onEdgePredicate->SetTolerance( _tol ); + _onEdgePredicate->SetMesh( _helper.GetMeshDS() ); + { + TopTools_IndexedMapOfShape edges; + TopExp::MapShapes( theShape, TopAbs_EDGE, edges ); + TopoDS_Compound eCompound; + BRep_Builder builder; + builder.MakeCompound( eCompound ); + for ( const TopoDS_Shape& e : edges ) + builder.Add( eCompound, e ); + + _onEdgePredicate->SetShape( eCompound, SMDSAbs_Node ); + } + return; +} + +//================================================================================ +/*! + * \brief Find or create a group of edges with given name + */ +//================================================================================ + +SMDS_MeshGroup* BLSURFPlugin_EnforcedMesh1D::getGroup( const std::string& groupName ) +{ + SMDS_MeshGroup* group = nullptr; + if ( !groupName.empty() ) + { + if ( _name2Group.count( groupName )) + return _name2Group[ groupName ]; + + // find existing group + for ( SMESH_Mesh::GroupIteratorPtr grIt = _mesh->GetGroups(); grIt->more(); ) + { + SMESH_Group* grp = grIt->next(); + SMESHDS_Group* grpDS = dynamic_cast< SMESHDS_Group* >( grp->GetGroupDS() ); + if ( grpDS && + grpDS->GetType() == SMDSAbs_Edge && + groupName == grp->GetName() ) + { + _name2Group[ groupName ] = & grpDS->SMDSGroup(); + return & grpDS->SMDSGroup(); + } + } + + // create a new group + SMESH_Group* grp = _mesh->AddGroup( SMDSAbs_Edge, groupName.c_str() ); + SMESHDS_Group* grpDS = static_cast< SMESHDS_Group* >( grp->GetGroupDS() ); + + group = & grpDS->SMDSGroup(); + _name2Group[ groupName ] = group; + } + return group; +} + +//================================================================================ +/*! + * \brief Look for a node dividing a given EDGE + */ +//================================================================================ + +const SMDS_MeshNode* BLSURFPlugin_EnforcedMesh1D::findNodeOnEdge( const gp_Pnt& p, + const TopoDS_Edge& edge ) +{ + // look for an equal node on the EDGE + if ( std::vector< const SMDS_MeshNode* >* nodesOnE = _nodesOnEdge.ChangeSeek( edge )) + for ( const SMDS_MeshNode* n : *nodesOnE ) + if ( p.SquareDistance( SMESH_NodeXYZ( n )) < _tol * _tol ) + { + return n; + } + + return nullptr; +} + +//================================================================================ +/*! + * \brief Add a node to an EDGE + */ +//================================================================================ + +void BLSURFPlugin_EnforcedMesh1D::addNodeOnEdge( const SMDS_MeshNode* node, + const TopoDS_Edge& edge, + const double u) +{ + _mesh->GetMeshDS()->SetNodeOnEdge( node, edge, u ); + + std::vector< const SMDS_MeshNode* > * nodesOnE = _nodesOnEdge.ChangeSeek( edge ); + if ( !nodesOnE ) + nodesOnE = _nodesOnEdge.Bound( edge, std::vector< const SMDS_MeshNode* >() ); + + nodesOnE->push_back( node ); +} + +//================================================================================ +/*! + * \brief Create EDGEs by dividing a given EDGE by nodes on it + * \param [in] edge - the EDGE to divide + * \param [in] nodes - the nodes to divide by + */ +//================================================================================ + +void BLSURFPlugin_EnforcedMesh1D:: + +splitEdgeByNodes( TopoDS_Edge edge, const std::vector< const SMDS_MeshNode* >& nodes ) +{ + if ( nodes.empty() ) + return; + + edge.Orientation( TopAbs_FORWARD ); + + TopoDS_Vertex v0 = _helper.IthVertex( 0, edge ); + TopoDS_Vertex v1 = _helper.IthVertex( 1, edge ); + + // create VERTEXes and sort them along the EDGE + + std::map< double, TopoDS_Vertex > sortedVertices; + + BRepAdaptor_Curve curve( edge ); + for ( SMESH_NodeXYZ pn : nodes ) + { + gp_Pnt projPnt; + double u; + ShapeAnalysis_Curve().Project( curve, pn, _tol, projPnt, u, false ); + projPnt = curve.Value( u ); + + TopoDS_Vertex v = BRepBuilderAPI_MakeVertex( projPnt ); + + sortedVertices.insert({ u, v }); + + _nOnE2Vertex[ pn.Node() ] = v; + } + sortedVertices.insert({ BRep_Tool::Parameter( v1, edge ), v1 }); + + + // create EDGEs + + BRep_Builder builder; + std::vector< TopoDS_Edge >& newEdges = *_edgeSplitsOfEdge.Bound( edge, TEdge2Edges::value_type()); + + double u0 = BRep_Tool::Parameter( v0, edge ); + for ( auto& u2v : sortedVertices ) + { + double u1 = u2v.first; + v1 = u2v.second; + + TopoDS_Shape newShape = edge.EmptyCopied(); + TopoDS_Edge newEdge = TopoDS::Edge( newShape ); + builder.Add( newEdge, v0 ); + builder.Add( newEdge, v1 ); + builder.Range( newEdge, u0, u1 ); + newEdges.push_back( newEdge ); + + v0 = v1; + u0 = u1; + } + + return; +} + +//================================================================================ +/*! + * \brief Return true if there are enforced segments on a FACE. Start iteration on segments + */ +//================================================================================ + +bool BLSURFPlugin_EnforcedMesh1D::HasSegmentsOnFace( const TopoDS_Face& face ) +{ + _segIterator.reset(); + + if ( _faces.Contains( face )) + { + _currentFace = face; + _segIterator = _helper.GetMeshDS()->MeshElements( face )->GetElements(); + + _helper.SetSubShape( face ); + + return _segIterator->more(); + } + return false; +} + + +//================================================================================ +/*! + * \brief Return next segment on the FACE + */ +//================================================================================ + +bool BLSURFPlugin_EnforcedMesh1D::NextSegment( Segmemnt & seg, + TopTools_IndexedMapOfShape & vertexTags ) +{ + if ( _segIterator && _segIterator->more() ) + { + const SMDS_MeshElement* segment = _segIterator->next(); + + while ( segment->GetType() != SMDSAbs_Edge && _segIterator->more() ) + segment = _segIterator->next(); + if ( segment->GetType() != SMDSAbs_Edge ) + return false; + + const SMDS_MeshNode * node[2] = { segment->GetNode(0), + segment->GetNode(1) }; + + seg._tag = _segTag++; + + seg._xyz[0] = SMESH_NodeXYZ( node[0]); + seg._xyz[1] = SMESH_NodeXYZ( node[1]); + + seg._uv[0] = _helper.GetNodeUV( _currentFace, node[0], node[1] ); + seg._uv[1] = _helper.GetNodeUV( _currentFace, node[1], node[0] ); + + seg._pcurve = new Geom2d_Line( seg._uv[0], ( seg._uv[1] - seg._uv[0] )); + + seg._u[0] = 0.0; + seg._u[1] = ( seg._uv[1] - seg._uv[0] ).Modulus(); + + for ( int i = 0; i < 2; ++i ) + { + auto n2v = _nOnE2Vertex.find( node[i] ); // find VERTEX by node + + if ( n2v != _nOnE2Vertex.end() ) + seg._vTag[i] = vertexTags.Add( n2v->second ); + else + seg._vTag[i] = _nodeTag0 + _nodeTags.Add( node[i] ); + } + + if ( !_isQuadratic ) + _mesh->GetMeshDS()->UnSetMeshElementOnShape( segment, _currentFace ); + + return true; + } + return false; +} + +//================================================================================ +/*! + * \brief Return enforced node by the tag that was returned by Segmemnt::_vTag[i] + */ +//================================================================================ + +const SMDS_MeshNode* +BLSURFPlugin_EnforcedMesh1D::GetNodeByTag( int tag, + const TopTools_IndexedMapOfShape & vertexTags ) +{ + const SMDS_MeshNode* node = nullptr; + + if ( tag <= vertexTags.Size() && !_nOnE2Vertex.empty() ) + { + const TopoDS_Shape& vertex = vertexTags( tag ); + + for ( auto n2v = _nOnE2Vertex.begin(); n2v != _nOnE2Vertex.end(); ++n2v ) + if ( vertex.IsSame( n2v->second )) + { + node = n2v->first; + _nOnE2Vertex.erase( n2v ); + return node; + } + } + + tag -= _nodeTag0; + + bool isValid = ( 0 < tag && tag <= _nodeTags.Size() ); + if ( isValid ) + node = _nodeTags( tag ); + + return node; +} + +//================================================================================ +/*! + * \brief Return true if a tag corresponds to the tag of enforced segment + * that was returned by Segment::_tag + */ +//================================================================================ + +bool BLSURFPlugin_EnforcedMesh1D::IsSegmentTag( int tag ) const +{ + return ( _segTag0 <= tag && tag <= _segTag ); +} + +//================================================================================ +/*! + * \brief Return tag of EDGE by tags of its splits + */ +//================================================================================ + +int BLSURFPlugin_EnforcedMesh1D::GetTagOfSplitEdge( int splitTag ) const +{ + auto sTag2eTag = _splitTags2EdgeTag.find( splitTag ); + return ( sTag2eTag == _splitTags2EdgeTag.end() ) ? splitTag : sTag2eTag->second; +} diff --git a/src/BLSURFPlugin/BLSURFPlugin_EnforcedMesh1D.hxx b/src/BLSURFPlugin/BLSURFPlugin_EnforcedMesh1D.hxx new file mode 100644 index 0000000..aac128d --- /dev/null +++ b/src/BLSURFPlugin/BLSURFPlugin_EnforcedMesh1D.hxx @@ -0,0 +1,172 @@ +// Copyright (C) 2007-2021 CEA/DEN, EDF R&D +// +// 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 +// +// File : BLSURFPlugin_EnforcedMesh1D.hxx +// Author : Edward AGAPOV (OCC) + +#ifndef __BLSURFPlugin_EnforcedMesh1D_HXX__ +#define __BLSURFPlugin_EnforcedMesh1D_HXX__ + +#include "BLSURFPlugin_Hypothesis.hxx" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +class SMDS_MeshElement; +class SMDS_MeshGroup; +class SMDS_MeshNode; +class SMESH_Mesh; + +/*! + * \brief Implement 1D mesh into the mesh made by MG-CADSurf + */ +class BLSURFPlugin_EnforcedMesh1D +{ +public: + + BLSURFPlugin_EnforcedMesh1D( SMESH_MesherHelper& helper, + const BLSURFPlugin_Hypothesis* hyp ); + + ~BLSURFPlugin_EnforcedMesh1D(); + + // Return EDGEs resulted from division of FACE boundary by enforced segments + bool GetSplitsOfEdge( const TopoDS_Edge& edge, + std::vector< TopoDS_Edge > & splits, + TopTools_IndexedMapOfShape & edgeTags ); + + // Return true if there are enforced segments on a FACE. Start iteration on segments + bool HasSegmentsOnFace( const TopoDS_Face& face ); + + // Data of an enforced segment to provide MG-CADSurf with + struct Segmemnt + { + int _tag; + Handle(Geom2d_Curve) _pcurve; + + // data of two ends + double _u [2]; + gp_XY _uv [2]; + gp_XYZ _xyz [2]; + int _vTag[2]; + }; + + // Return next segment on the FACE. Iteration starts upon calling HasSegmentsOnFace() + bool NextSegment( Segmemnt & seg, TopTools_IndexedMapOfShape & vertexTags ); + + // Return enforced node by tag + const SMDS_MeshNode* GetNodeByTag( int tag, const TopTools_IndexedMapOfShape & vertexTags ); + + // Return true if a tad corresponds to an enforced segment + bool IsSegmentTag( int tag ) const; + + // Return tag of EDGE by tags of its splits + int GetTagOfSplitEdge( int splitTag ) const; + + typedef std::map< const SMDS_MeshElement* , std::vector< const SMDS_MeshNode* > > TNodesOnSeg; + +private: + + void copyEnforcedMesh( const BLSURFPlugin_Hypothesis::EnforcedMesh& theEnfMesh, + const BLSURFPlugin_Hypothesis* theHyp, + const TopoDS_Shape& theShape); + + const SMDS_MeshNode* copyEnforcedNode( const SMDS_MeshNode* enfNode ); + + void setupPredicates( const TopoDS_Shape& shape ); + + void splitSegmentOnSeveralShapes( const SMDS_MeshElement* segment ); + + void splitSelfIntersectingSegments( const TopoDS_Shape & face ); + + void findIntersectionWithSeamEdge( const TopoDS_Face & face, TNodesOnSeg & segInternalNodes ); + + bool intersectSegments( const SMDS_MeshElement* seg1, const SMDS_MeshElement* seg2, + const TopoDS_Face& face, gp_Pnt& intPnt, gp_Pnt2d& inUV ) const; + + gp_Pnt getEdgeIntersection( const TopoDS_Shape& faceOrEdge, + const gp_XYZ& xyz0, const gp_XYZ& xyz1, + TopoDS_Edge & edge, double & paramOnEdge ); + + void splitEdgeByNodes( TopoDS_Edge edge, const std::vector< const SMDS_MeshNode* >& nodes); + + SMDS_MeshGroup* getGroup( const std::string& groupName ); + + const SMDS_MeshNode* findNodeOnEdge( const gp_Pnt& p, const TopoDS_Edge& edge ); + void addNodeOnEdge( const SMDS_MeshNode*node , const TopoDS_Edge& edge, const double u = 0. ); + + + SMESH_Mesh* _mesh; + TopoDS_Shape _shape; + SMESH_MesherHelper _helper; + bool _isQuadratic; + std::map< std::string, SMDS_MeshGroup* > _name2Group; + double _tol; + TopTools_IndexedMapOfShape _faces; + + // segments whose nodes are on different FACEs; + // such segments will be split into segments lying each on own FACE + std::vector< const SMDS_MeshElement* > _segmentsOnSeveralShapes; + + // nodes projected on EDGEs; EDGEs will be divided by them + typedef NCollection_DataMap< TopoDS_Edge, + std::vector< const SMDS_MeshNode* >, + TopTools_ShapeMapHasher> TEdge2Nodes; + typedef NCollection_DataMap< TopoDS_Edge, + std::vector< TopoDS_Edge >, + TopTools_ShapeMapHasher> TEdge2Edges; + TEdge2Nodes _nodesOnEdge; + TEdge2Edges _edgeSplitsOfEdge; // result of EDGE division by nodes + std::map< int, int > _splitTags2EdgeTag; + std::map< const SMDS_MeshNode* , TopoDS_Vertex > _nOnE2Vertex; // VERTEXes on _nodesOnEdge + + typedef SMESH::Controls::ElementsOnShape TPredicate; + typedef SMESH::Controls::ElementsOnShapePtr TPredicatePtr; + TPredicatePtr _onVertexPredicate; + TPredicatePtr _onEdgePredicate; + + // for iteration of segments of FACE + + SMDS_ElemIteratorPtr _segIterator; + TopoDS_Face _currentFace; + int _segTag0; + int _segTag; + + typedef NCollection_IndexedMap< const SMDS_MeshNode* > TNodeIndMap; + TNodeIndMap _nodeTags; + int _nodeTag0; + + // nodes not projected to geometry; they are reused during next projection to geometry + std::vector< const SMDS_MeshNode* > _freeNodes; + +}; + + +#endif diff --git a/src/BLSURFPlugin/BLSURFPlugin_Hypothesis.cxx b/src/BLSURFPlugin/BLSURFPlugin_Hypothesis.cxx index 9b85b3b..bc094a3 100644 --- a/src/BLSURFPlugin/BLSURFPlugin_Hypothesis.cxx +++ b/src/BLSURFPlugin/BLSURFPlugin_Hypothesis.cxx @@ -26,16 +26,18 @@ // #include "BLSURFPlugin_Hypothesis.hxx" #include "BLSURFPlugin_Attractor.hxx" -#include "SMESH_Gen_i.hxx" -#include -#include -#include -#include + +#include +#include +#include +#include +#include #include +#include // cascade include -#include "ShapeAnalysis.hxx" +#include // CORBA includes #include CORBA_CLIENT_HEADER(SALOMEDS) @@ -974,6 +976,63 @@ int BLSURFPlugin_Hypothesis::GetHyperPatchTag( const int fa } return faceTag; } + +//============================================================================= +void BLSURFPlugin_Hypothesis::SetEnforcedMeshes( std::vector< EnforcedMesh > & enforcedMeshes ) +{ + if ( _enforcedMeshes != enforcedMeshes ) + { + _enforcedMeshes.swap( enforcedMeshes ); + NotifySubMeshesHypothesisModification(); + } +} + +//================================================================================ +/*! + * \brief Return elements of 1D enforced mesh. Result can be NULL + */ +//================================================================================ + +SMDS_ElemIteratorPtr +BLSURFPlugin_Hypothesis::GetEnforcedSegments( const EnforcedMesh& enfMesh, + SMESH_Mesh* & mesh ) const +{ + SMDS_ElemIteratorPtr it; + if (( mesh = SMESH_Hypothesis::GetMeshByPersistentID( enfMesh._meshID ))) + { + mesh->Load(); + + switch( enfMesh._type ) + { + case ENFORCED_MESH: + it = mesh->GetMeshDS()->elementsIterator( SMDSAbs_Edge ); + break; + + case ENFORCED_GROUP: + if ( SMESH_Group* grp = mesh->GetGroup( enfMesh._subID )) + { + if ( grp->GetGroupDS()->GetType() == SMDSAbs_Edge ) + it = grp->GetGroupDS()->GetElements(); + } + break; + + case ENFORCED_SUBMESH: + if ( SMESH_subMesh* sm = mesh->GetSubMeshContaining( enfMesh._subID )) + if ( SMESHDS_SubMesh * smDS = sm->GetSubMeshDS() ) + { + it = smDS->GetElements(); + if ( it->more() && it->next()->GetType() != SMDSAbs_Edge ) + it = SMDS_ElemIteratorPtr(); + else + it = smDS->GetElements(); + } + break; + } + } + return it; +} + + //============================================================================= void BLSURFPlugin_Hypothesis::SetPreCADMergeEdges(bool theVal) { @@ -2292,8 +2351,13 @@ std::ostream & BLSURFPlugin_Hypothesis::SaveTo(std::ostream & save) std::ostringstream hpStream; boost::archive::text_oarchive( hpStream ) << _hyperPatchEntriesList; std::string hpString = hpStream.str(); - save << " " << hpString.size() << " " << hpString; + SMESHDS_Hypothesis::SaveString( save, hpString ); + // Enforced meshes + std::ostringstream enfMStream; + boost::archive::text_oarchive( enfMStream ) << _enforcedMeshes; + std::string enfMString = enfMStream.str(); + SMESHDS_Hypothesis::SaveString( save, enfMString ); return save; } @@ -3328,23 +3392,52 @@ std::istream & BLSURFPlugin_Hypothesis::LoadFrom(std::istream & load) } // hyper-patches as entries (issue bos #20543) - if ( static_cast( load >> i ) && i > 0 ) + std::string buffer; + if ( SMESHDS_Hypothesis::LoadString( load, buffer )) { - std::string buffer( i, '\0' ); - load.get( buffer[0] ); // remove a white-space - load.get( & buffer[0], i + 1 ); + std::istringstream istream( buffer.data() ); + boost::archive::text_iarchive archive( istream ); + SMESH_TRY; + archive >> _hyperPatchEntriesList; + SMESH_CATCH( SMESH::printErrorInDebugMode ); + } + // Enforced meshes (issue bos $16292) + buffer.clear(); + if ( SMESHDS_Hypothesis::LoadString( load, buffer )) + { std::istringstream istream( buffer.data() ); boost::archive::text_iarchive archive( istream ); - try { - archive >> _hyperPatchEntriesList; - } - catch (...) {} + SMESH_TRY; + archive >> _enforcedMeshes; + SMESH_CATCH( SMESH::printErrorInDebugMode ); } return load; } +namespace boost { + namespace serialization { + + //======================================================================= + //function : serialize + //purpose : serialize EnforcedMesh + //======================================================================= + + template + void serialize(Archive & ar, BLSURFPlugin_Hypothesis::EnforcedMesh & enfM, + const unsigned int /*version*/) + { + ar & enfM._meshID; + ar & enfM._subID; + ar & enfM._type; + ar & enfM._groupName; + } + + } // namespace serialization +} // namespace boost + + void BLSURFPlugin_Hypothesis::LoadFacesPeriodicity(std::istream & load) { bool isOK = true; diff --git a/src/BLSURFPlugin/BLSURFPlugin_Hypothesis.hxx b/src/BLSURFPlugin/BLSURFPlugin_Hypothesis.hxx index 134a51d..693def6 100644 --- a/src/BLSURFPlugin/BLSURFPlugin_Hypothesis.hxx +++ b/src/BLSURFPlugin/BLSURFPlugin_Hypothesis.hxx @@ -27,20 +27,23 @@ #ifndef _BLSURFPlugin_Hypothesis_HXX_ #define _BLSURFPlugin_Hypothesis_HXX_ -#include "SMESH_Hypothesis.hxx" +#include "BLSURFPlugin_Attractor.hxx" + +#include +#include +#include + #include #include #include -#include #include -#include -#include -#include -#include -#include "BLSURFPlugin_Attractor.hxx" + +class SMESH_Mesh; // Parameters for work of MG-CADSurf +enum EnforcedMeshType { ENFORCED_MESH, ENFORCED_GROUP, ENFORCED_SUBMESH }; + class BLSURFPlugin_Hypothesis: public SMESH_Hypothesis { public: @@ -221,9 +224,9 @@ public: std::string GetTags(); // Hyper-patches - typedef std::set< int > THyperPatchTags; - typedef std::vector< THyperPatchTags > THyperPatchList; - typedef std::set< std::string > THyperPatchEntries; + typedef std::set< int > THyperPatchTags; + typedef std::vector< THyperPatchTags > THyperPatchList; + typedef std::set< std::string > THyperPatchEntries; typedef std::vector< THyperPatchEntries > THyperPatchEntriesList; void SetHyperPatches(const THyperPatchList& hpl, bool notifyMesh=true); @@ -234,6 +237,29 @@ public: const THyperPatchEntriesList& GetHyperPatchEntries() const { return _hyperPatchEntriesList; } static int GetHyperPatchTag( int faceTag, const BLSURFPlugin_Hypothesis* hyp, int* iPatch=0 ); + // Enforced mesh + struct EnforcedMesh + { + int _meshID; // persistent mesh ID + int _subID; // either persistent group ID or sub-shape ID for sub-mesh + EnforcedMeshType _type; /* specify what _subID means: + - nothing for ENFORCED_MESH + - group ID for ENFORCED_GROUP + - sub-shape ID for ENFORCED_SUBMESH */ + std::string _groupName; // name of a group to add mesh edges to + + bool operator==(const EnforcedMesh& em ) const + { + return ( _meshID == em._meshID && _subID == em._subID && + _type == em._type && _groupName == em._groupName ); + } + }; + + void SetEnforcedMeshes( std::vector< EnforcedMesh > & enforcedMeshes ); + const std::vector< EnforcedMesh > & GetEnforcedMeshes() const { return _enforcedMeshes; } + SMDS_ElemIteratorPtr GetEnforcedSegments( const EnforcedMesh& enfMesh, + SMESH_Mesh* & mesh ) const; + void SetPreCADMergeEdges(bool theVal); bool GetPreCADMergeEdges() const { return _preCADMergeEdges; } @@ -647,30 +673,32 @@ private: TSizeMap _attractors; TAttractorMap _classAttractors; - TFaceEntryEnfVertexListMap _faceEntryEnfVertexListMap; - TEnfVertexList _enfVertexList; + TFaceEntryEnfVertexListMap _faceEntryEnfVertexListMap; + TEnfVertexList _enfVertexList; // maps to get "manual" enf vertex (through their coordinates) - TFaceEntryCoordsListMap _faceEntryCoordsListMap; - TCoordsEnfVertexMap _coordsEnfVertexMap; + TFaceEntryCoordsListMap _faceEntryCoordsListMap; + TCoordsEnfVertexMap _coordsEnfVertexMap; // maps to get "geom" enf vertex (through their geom entries) - TFaceEntryEnfVertexEntryListMap _faceEntryEnfVertexEntryListMap; - TEnfVertexEntryEnfVertexMap _enfVertexEntryEnfVertexMap; - TGroupNameNodeIDMap _groupNameNodeIDMap; + TFaceEntryEnfVertexEntryListMap _faceEntryEnfVertexEntryListMap; + TEnfVertexEntryEnfVertexMap _enfVertexEntryEnfVertexMap; + TGroupNameNodeIDMap _groupNameNodeIDMap; // Enable internal enforced vertices on specific face if requested by user // TFaceEntryInternalVerticesList _faceEntryInternalVerticesList; - bool _enforcedInternalVerticesAllFaces; - TEnfGroupName _enforcedInternalVerticesAllFacesGroup; + bool _enforcedInternalVerticesAllFaces; + TEnfGroupName _enforcedInternalVerticesAllFacesGroup; - TPreCadPeriodicityVector _preCadFacesPeriodicityVector; - TPreCadPeriodicityVector _preCadEdgesPeriodicityVector; + TPreCadPeriodicityVector _preCadFacesPeriodicityVector; + TPreCadPeriodicityVector _preCadEdgesPeriodicityVector; + + TFacesPeriodicityVector _facesPeriodicityVector; + TEdgesPeriodicityVector _edgesPeriodicityVector; + TVerticesPeriodicityVector _verticesPeriodicityVector; - TFacesPeriodicityVector _facesPeriodicityVector; - TEdgesPeriodicityVector _edgesPeriodicityVector; - TVerticesPeriodicityVector _verticesPeriodicityVector; + THyperPatchList _hyperPatchList; + THyperPatchEntriesList _hyperPatchEntriesList; - THyperPatchList _hyperPatchList; - THyperPatchEntriesList _hyperPatchEntriesList; + std::vector< EnforcedMesh > _enforcedMeshes; // enforced 1D meshes // Called by SaveTo to store content of _preCadFacesPeriodicityVector and _preCadEdgesPeriodicityVector void SavePreCADPeriodicity(std::ostream & save, const char* shapeType); diff --git a/src/BLSURFPlugin/BLSURFPlugin_Hypothesis_i.cxx b/src/BLSURFPlugin/BLSURFPlugin_Hypothesis_i.cxx index fe72d2e..5a90eb0 100644 --- a/src/BLSURFPlugin/BLSURFPlugin_Hypothesis_i.cxx +++ b/src/BLSURFPlugin/BLSURFPlugin_Hypothesis_i.cxx @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -40,6 +41,142 @@ using namespace std; +namespace +{ + //================================================================================ + /*! + * \brief Return persistent ID of a mesh + * \param [in] mesh - the mesh + * \return int - -1 in case of failure + */ + //================================================================================ + + int GetMeshPersistentId( SMESH::SMESH_Mesh_ptr mesh ) + { + int id = -1; + if ( SMESH_Mesh_i* mesh_i = SMESH::DownCast( mesh )) + id = mesh_i->GetImpl().GetMeshDS()->GetPersistentId(); + return id; + } + + //================================================================================ + /*! + * \brief Return persistent ID of a group or sub-mesh + * \param [in] meshPart - the mesh part + * \param [out] isGroup - return true if meshPart is a group + * \return int - -1 in case if meshPart is neither a group nor a sub-mesh + */ + //================================================================================ + + int GetMeshPartPersistentId( SMESH::SMESH_IDSource_ptr meshPart, bool & isGroup ) + { + int id = -1; + isGroup = false; + SMESH_GroupBase_i* group_i = SMESH::DownCast( meshPart ); + if ( group_i ) + { + id = group_i->GetLocalID(); + isGroup = true; + } + else + { + SMESH::SMESH_subMesh_var subMesh = SMESH::SMESH_subMesh::_narrow( meshPart ); + if ( !subMesh->_is_nil() ) + id = subMesh->GetId(); + } + return id; + } + + //================================================================================ + /*! + * \brief Find a mesh in the study by mesh persistent ID + */ + //================================================================================ + + SMESH::SMESH_Mesh_ptr FindMeshByID( int theMeshID ) + { + SMESH::SMESH_Mesh_var mesh; + + SMESH_Gen_i* gen = SMESH_Gen_i::GetSMESHGen(); + CORBA::String_var compDataType = gen->ComponentDataType(); + SALOMEDS::Study_var aStudy = gen->getStudyServant(); + SALOMEDS::SComponent_wrap genSO = aStudy->FindComponent( compDataType.in() ); + if ( !genSO->_is_nil() ) + { + SALOMEDS::ChildIterator_wrap anIter = aStudy->NewChildIterator( genSO ); + for ( ; anIter->More(); anIter->Next() ) + { + SALOMEDS::SObject_wrap so = anIter->Value(); + CORBA::Object_var obj = gen->SObjectToObject( so ); + mesh = SMESH::SMESH_Mesh::_narrow( obj ); + if ( !mesh->_is_nil() && GetMeshPersistentId( mesh ) == theMeshID ) + break; + mesh = SMESH::SMESH_Mesh::_nil(); + } + } + return mesh._retn(); + } + + //================================================================================ + /*! + * \brief Return a group by its ID + */ + //================================================================================ + + SMESH::SMESH_GroupBase_ptr GetGroupByID( SMESH::SMESH_Mesh_ptr mesh, int ID ) + { + SMESH::SMESH_GroupBase_var group; + if ( !CORBA::is_nil( mesh )) + { + SMESH::ListOfGroups_var groups = mesh->GetGroups(); + for ( CORBA::ULong i = 0; i < groups->length(); ++i ) + if ( SMESH_GroupBase_i* group_i = SMESH::DownCast( groups[i] )) + if ( group_i->GetLocalID() == ID ) + { + group = SMESH::SMESH_GroupBase::_narrow( groups[i] ); + break; + } + } + return group._retn(); + } + + //================================================================================ + /*! + * \brief Return a sub-mesh by sub-shape ID + */ + //================================================================================ + + SMESH::SMESH_subMesh_ptr GetSubMeshByID( SMESH::SMESH_Mesh_ptr mesh, + const int shapeID, + CORBA::Long subMeshTag ) + { + SMESH::SMESH_subMesh_var subMesh; + if ( !CORBA::is_nil( mesh )) + { + SMESH_Gen_i* gen = SMESH_Gen_i::GetSMESHGen(); + SALOMEDS::SObject_wrap meshSO = gen->ObjectToSObject( mesh ); + SALOMEDS::Study_var aStudy = gen->getStudyServant(); + SALOMEDS::SObject_wrap subMeshRootSO; + if ( !meshSO->_is_nil() && meshSO->FindSubObject( subMeshTag, subMeshRootSO.inout() )) + { + SALOMEDS::ChildIterator_wrap anIter = aStudy->NewChildIterator( subMeshRootSO ); + for ( ; anIter->More(); anIter->Next() ) + { + SALOMEDS::SObject_wrap so = anIter->Value(); + CORBA::Object_var obj = gen->SObjectToObject( so ); + subMesh = SMESH::SMESH_subMesh::_narrow( obj ); + if ( !subMesh->_is_nil() && subMesh->GetId() == shapeID ) + break; + subMesh = SMESH::SMESH_subMesh::_nil(); + } + } + return subMesh._retn(); + } + return subMesh._retn(); + } + +} // namespace + //============================================================================= /*! * BLSURFPlugin_Hypothesis_i::BLSURFPlugin_Hypothesis_i @@ -921,6 +1058,104 @@ CORBA::Short BLSURFPlugin_Hypothesis_i::GetVerbosity() { return (CORBA::Short) this->GetImpl()->GetVerbosity(); } + +//============================================================================= +void BLSURFPlugin_Hypothesis_i::SetEnforcedMeshes(const BLSURFPlugin::EnforcedMeshesList& theMeshes ) +{ + std::vector< ::BLSURFPlugin_Hypothesis::EnforcedMesh > enforcedMeshes; + for ( CORBA::ULong i = 0; i < theMeshes.length(); ++i ) + { + const BLSURFPlugin::MG_EnforcedMesh1D & inEM = theMeshes[ i ]; + if ( CORBA::is_nil( inEM.mesh )) + THROW_SALOME_CORBA_EXCEPTION( "NULL enforced mesh",SALOME::BAD_PARAM ); + + SMESH::SMESH_Mesh_var mesh = inEM.mesh->GetMesh(); + if ( CORBA::is_nil( mesh )) + THROW_SALOME_CORBA_EXCEPTION( "BAD enforced mesh",SALOME::BAD_PARAM ); + + int meshID = GetMeshPersistentId( mesh ); + if ( meshID < 0 ) + THROW_SALOME_CORBA_EXCEPTION( "BAD enforced mesh",SALOME::BAD_PARAM ); + + bool isGroup = false; + int partID = GetMeshPartPersistentId( inEM.mesh, isGroup ); + ::EnforcedMeshType partType = ENFORCED_MESH; + if ( partID > -1 ) + partType = isGroup ? ENFORCED_GROUP : ENFORCED_SUBMESH; + + enforcedMeshes.push_back({ meshID, partID, partType, inEM.groupName.in() }); + } + + this->GetImpl()->SetEnforcedMeshes( enforcedMeshes ); + + // dump + + SMESH::TPythonDump pyDump; + pyDump << BLSURFPlugin::BLSURFPlugin_Hypothesis_var( _this() ) + << ".SetEnforcedMeshes([ "; + + for ( CORBA::ULong i = 0; i < theMeshes.length(); ++i ) + { + const BLSURFPlugin::MG_EnforcedMesh1D & inEM = theMeshes[ i ]; + pyDump << "BLSURFPlugin.MG_EnforcedMesh1D( " << inEM.mesh.in() << ", "; + if ( inEM.groupName.in() && inEM.groupName.in()[0] ) + pyDump << "'" << inEM.groupName.in() << "'"; + else + pyDump << "''"; + pyDump << ")" << ( i + 1 < theMeshes.length() ? ", " : "])"); + } +} + +//============================================================================= + +BLSURFPlugin::EnforcedMeshesList* BLSURFPlugin_Hypothesis_i::GetEnforcedMeshes() +{ + const std::vector< ::BLSURFPlugin_Hypothesis::EnforcedMesh > & hypEnfMeshes = + this->GetImpl()->GetEnforcedMeshes(); + + BLSURFPlugin::EnforcedMeshesList_var outEnfMeshes = new BLSURFPlugin::EnforcedMeshesList(); + outEnfMeshes->length( hypEnfMeshes.size() ); + + int nbMeshes = 0; + for ( size_t i = 0; i < hypEnfMeshes.size(); ++i ) + { + const ::BLSURFPlugin_Hypothesis::EnforcedMesh& enfMeshData = hypEnfMeshes[ i ]; + BLSURFPlugin::MG_EnforcedMesh1D & outEnfMesh = outEnfMeshes[ nbMeshes ]; + + SMESH::SMESH_Mesh_var mesh = FindMeshByID( enfMeshData._meshID ); + switch ( enfMeshData._type ) { + case ENFORCED_MESH : + { + outEnfMesh.mesh = SMESH::SMESH_IDSource::_narrow( mesh ); + break; + } + case ENFORCED_GROUP : + { + SMESH::SMESH_GroupBase_var group = GetGroupByID( mesh, enfMeshData._subID ); + outEnfMesh.mesh = SMESH::SMESH_IDSource::_narrow( group ); + break; + } + case ENFORCED_SUBMESH: + { + SMESH::SMESH_subMesh_var subMesh; + subMesh = GetSubMeshByID( mesh, enfMeshData._subID, SMESH::Tag_SubMeshOnEdge ); + if ( CORBA::is_nil( subMesh )) + subMesh = GetSubMeshByID( mesh, enfMeshData._subID, SMESH::Tag_SubMeshOnCompound ); + + outEnfMesh.mesh = SMESH::SMESH_IDSource::_narrow( subMesh ); + break; + } + default: continue; + } + outEnfMesh.groupName = enfMeshData._groupName.c_str(); + + nbMeshes += ( !CORBA::is_nil( outEnfMesh.mesh )); + } + outEnfMeshes->length( nbMeshes ); + + return outEnfMeshes._retn(); +} + //============================================================================= void BLSURFPlugin_Hypothesis_i::SetEnforceCadEdgesSize( CORBA::Boolean toEnforce ) { diff --git a/src/BLSURFPlugin/BLSURFPlugin_Hypothesis_i.hxx b/src/BLSURFPlugin/BLSURFPlugin_Hypothesis_i.hxx index 5b6c749..00f3bed 100644 --- a/src/BLSURFPlugin/BLSURFPlugin_Hypothesis_i.hxx +++ b/src/BLSURFPlugin/BLSURFPlugin_Hypothesis_i.hxx @@ -173,6 +173,12 @@ public: void SetVerbosity(CORBA::Short theVal); CORBA::Short GetVerbosity(); + /*! + * Set/Get enforced 1D meshes + */ + void SetEnforcedMeshes( const BLSURFPlugin::EnforcedMeshesList& enforcedMeshes ); + BLSURFPlugin::EnforcedMeshesList* GetEnforcedMeshes(); + void SetEnforceCadEdgesSize( CORBA::Boolean toEnforce ); CORBA::Boolean GetEnforceCadEdgesSize(); diff --git a/src/BLSURFPlugin/CMakeLists.txt b/src/BLSURFPlugin/CMakeLists.txt index 62d0fc4..a58e725 100644 --- a/src/BLSURFPlugin/CMakeLists.txt +++ b/src/BLSURFPlugin/CMakeLists.txt @@ -73,6 +73,7 @@ SET(BLSURFEngine_HEADERS BLSURFPlugin_Hypothesis.hxx BLSURFPlugin_Hypothesis_i.hxx BLSURFPlugin_Attractor.hxx + BLSURFPlugin_EnforcedMesh1D.hxx ) # --- sources --- @@ -85,6 +86,7 @@ SET(BLSURFEngine_SOURCES BLSURFPlugin_Hypothesis_i.cxx BLSURFPlugin_i.cxx BLSURFPlugin_Attractor.cxx + BLSURFPlugin_EnforcedMesh1D.cxx ) # --- scripts --- diff --git a/src/GUI/BLSURFPluginGUI_HypothesisCreator.cxx b/src/GUI/BLSURFPluginGUI_HypothesisCreator.cxx index c21e967..7e0870a 100644 --- a/src/GUI/BLSURFPluginGUI_HypothesisCreator.cxx +++ b/src/GUI/BLSURFPluginGUI_HypothesisCreator.cxx @@ -83,7 +83,8 @@ enum { STD_TAB = 0, ADV_TAB, SMP_TAB, - ENF_TAB, + ENF_V_TAB, + ENF_M_TAB, PERIODICITY_TAB, HYPERPATCH_TAB, SMP_NAME_COLUMN =0, @@ -104,7 +105,11 @@ enum { ENF_VER_ENTRY_COLUMN, ENF_VER_GROUP_COLUMN, ENF_VER_NB_COLUMNS, -// Periodicity + + // Enforced 1D meshes + ENF_MESH_NB_COLUMNS = 2, + + // Periodicity PERIODICITY_OBJ_SOURCE_COLUMN = 0, PERIODICITY_OBJ_TARGET_COLUMN, PERIODICITY_P1_SOURCE_COLUMN, @@ -713,39 +718,39 @@ QFrame* BLSURFPluginGUI_HypothesisCreator::buildFrame() lay->addWidget( myTabWidget ); myName = 0; - + // basic parameters myStdGroup = new QWidget(); QGridLayout* aStdLayout = new QGridLayout( myStdGroup ); aStdLayout->setSpacing( 6 ); aStdLayout->setMargin( 11 ); - + if( isCreation() ) myName = new QLineEdit( myStdGroup ); myStdWidget = new BLSURFPluginGUI_StdWidget(myStdGroup); if ( !hasGeom() ) { myStdWidget->myPhysicalMesh->removeItem( PhysicalLocalSize ); } - + int row = 0; if( isCreation() ) { aStdLayout->addWidget( new QLabel( tr( "SMESH_NAME" ), myStdGroup ), 0, 0, 1, 1 ); aStdLayout->addWidget( myName, row++, 1, 1, 3 ); } aStdLayout->addWidget( myStdWidget, row++, 0, 1, 4 ); - + row = 0; if( isCreation() ) row = 1; aStdLayout->setRowStretch(row,1); aStdLayout->setColumnStretch(1,1); - + // advanced parameters myAdvGroup = new QWidget(); QGridLayout* anAdvLayout = new QGridLayout( myAdvGroup ); anAdvLayout->setSpacing( 6 ); - anAdvLayout->setMargin( 11 ); + anAdvLayout->setMargin( 11 ); myAdvWidget = new BLSURFPluginGUI_AdvWidget(myAdvGroup); anAdvLayout->addWidget( myAdvWidget ); @@ -756,7 +761,7 @@ QFrame* BLSURFPluginGUI_HypothesisCreator::buildFrame() //Layout QGridLayout* anSmpLayout = new QGridLayout(mySmpGroup); - + // Table mySizeMapTable = new QTreeWidget( mySmpGroup ); mySizeMapTable ->setMinimumWidth(200); @@ -951,7 +956,7 @@ QFrame* BLSURFPluginGUI_HypothesisCreator::buildFrame() anEnfLayout->addWidget(myEnforcedTreeWidget, 0, 0, ENF_VER_NB_LINES, 1); QGridLayout* anEnfLayout2 = new QGridLayout(myEnfGroup); -// FACE AND VERTEX SELECTION + // FACE AND VERTEX SELECTION //anEnfLayout2->addWidget(myEnfFaceWdg, ENF_VER_FACE, 0, 1, 2); anEnfLayout2->addWidget(myEnfVertexWdg, ENF_VER_VERTEX, 0, 1, 2); anEnfLayout2->addWidget(myXCoordLabel, ENF_VER_X_COORD, 0, 1, 1); @@ -970,6 +975,56 @@ QFrame* BLSURFPluginGUI_HypothesisCreator::buildFrame() anEnfLayout2->setRowStretch(ENF_VER_NB_LINES+1, 1); anEnfLayout->addLayout(anEnfLayout2, 0,1,ENF_VER_NB_LINES+1,2); + // --------------------------- + // Enforced meshes parameters + // --------------------------- + + myEnfMeshGroup = new QWidget(); + QGridLayout* anEnfMeshLayout = new QGridLayout(myEnfMeshGroup); + + myEnfMeshTableWdg = new QTableWidget(myEnfGroup); + //myEnfMeshTableWdg->setRowCount( 0 ); + myEnfMeshTableWdg->setColumnCount( ENF_MESH_NB_COLUMNS ); + myEnfMeshTableWdg->setSortingEnabled(true); + myEnfMeshTableWdg->verticalHeader()->hide(); + myEnfMeshTableWdg->setHorizontalHeaderLabels( QStringList() + << tr( "ENF_NAME_COLUMN" ) + << tr( "ENF_GROUP_COLUMN" )); + myEnfMeshTableWdg->horizontalHeader()->setStretchLastSection(true); + myEnfMeshTableWdg->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive); + myEnfMeshTableWdg->setAlternatingRowColors(true); + myEnfMeshTableWdg->setSelectionMode(QAbstractItemView::ExtendedSelection); + myEnfMeshTableWdg->setSelectionBehavior(QAbstractItemView::SelectItems); + myEnfMeshTableWdg->resizeColumnsToContents(); + //myEnfMeshTableWdg->setItemDelegate(new EnforcedMeshTableWidgetDelegate()); + + myEnfMeshWdg = new StdMeshersGUI_ObjectReferenceParamWdg( SMESH::IDSOURCE_EDGE, myEnfMeshGroup, /*multiSel=*/false); + myEnfMeshWdg->SetDefaultText(tr("ENF_SELECT_MESH"), "QLineEdit { color: grey }"); + + myEnfMeshWdg->AvoidSimultaneousSelection(myEnfVertexWdg); + myEnfMeshWdg->AvoidSimultaneousSelection(myGeomSelWdg1); + myEnfMeshWdg->AvoidSimultaneousSelection(myGeomSelWdg2); + myEnfMeshWdg->AvoidSimultaneousSelection(myAttSelWdg); + + QLabel* enforcedGroupNameLabel = new QLabel( tr( "ENF_GROUP_LABEL" ), myEnfMeshGroup ); + myEnforcedGroupName = new QLineEdit(myEnfMeshGroup); + + myAddEnfMeshButton = new QPushButton(tr("ENF_ADD"),myEnfMeshGroup); + myRemoveEnfMeshButton = new QPushButton(tr("ENF_REMOVE"),myEnfMeshGroup); + + QGridLayout* anEnfMeshLayout2 = new QGridLayout(myEnfMeshGroup); + anEnfMeshLayout2->addWidget(myEnfMeshWdg, 0, 0, 1, 2); + anEnfMeshLayout2->addWidget(enforcedGroupNameLabel, 1, 0, 1, 1); + anEnfMeshLayout2->addWidget(myEnforcedGroupName, 1, 1, 1, 1); + anEnfMeshLayout2->addWidget(myAddEnfMeshButton, 2, 0, 1, 2); + anEnfMeshLayout2->addWidget(myRemoveEnfMeshButton, 3, 0, 1, 2); + anEnfMeshLayout2->setRowStretch( 4, 1 ); + + anEnfMeshLayout->addWidget(myEnfMeshTableWdg, 0, 0, 5, 1); + anEnfMeshLayout->addLayout(anEnfMeshLayout2, 0, 1, 1, 1); + anEnfMeshLayout->setRowStretch( 2, 1 ); + + // --- // Periodicity parameters myPeriodicityGroup = new QWidget( dlg() ); @@ -1200,7 +1255,8 @@ QFrame* BLSURFPluginGUI_HypothesisCreator::buildFrame() myTabWidget->insertTab( ADV_TAB, myAdvGroup, tr( "BLSURF_ADV_ARGS" ) ); if ( hasGeom() ) { myTabWidget->insertTab( SMP_TAB, mySmpGroup, tr( "LOCAL_SIZE" ) ); - myTabWidget->insertTab( ENF_TAB, myEnfGroup, tr( "BLSURF_ENF_VER" ) ); + myTabWidget->insertTab( ENF_V_TAB, myEnfGroup, tr( "BLSURF_ENF_VER" ) ); + myTabWidget->insertTab( ENF_M_TAB, myEnfMeshGroup, tr( "ENF_MESH" ) ); myTabWidget->insertTab( PERIODICITY_TAB, myPeriodicityGroup, tr( "BLSURF_PERIODICITY" ) ); myTabWidget->insertTab( HYPERPATCH_TAB, hpGroup, tr( "BLSURF_HYPERPATCH_TAB" )); } @@ -1208,47 +1264,55 @@ QFrame* BLSURFPluginGUI_HypothesisCreator::buildFrame() { mySmpGroup->hide(); myEnfGroup->hide(); + myEnfMeshGroup->hide(); myPeriodicityGroup->hide(); hpGroup->hide(); } myTabWidget->setCurrentIndex( STD_TAB ); - connect( myAdvWidget->addBtn, SIGNAL( clicked() ), this, SLOT( onAddOption() ) ); + connect( myAdvWidget->addBtn, SIGNAL( clicked() ), SLOT( onAddOption() ) ); // Size Maps - connect( addMapButton, SIGNAL( clicked()), this, SLOT( onAddMap() ) ); - connect( removeMapButton, SIGNAL( clicked()), this, SLOT( onRemoveMap() ) ); - connect( modifyMapButton, SIGNAL( clicked()), this, SLOT( onModifyMap() ) ); - connect( mySizeMapTable, SIGNAL( itemClicked (QTreeWidgetItem *, int)),this, SLOT( onSmpItemClicked(QTreeWidgetItem *, int) ) ); - connect( myGeomSelWdg2, SIGNAL( contentModified() ), this, SLOT( onMapGeomContentModified() ) ); - connect( myGeomSelWdg1, SIGNAL( contentModified() ), this, SLOT( onMapGeomContentModified() ) ); - connect( myAttSelWdg, SIGNAL( contentModified() ), this, SLOT( onMapGeomContentModified() ) ); - connect( mySizeMapTable, SIGNAL( itemChanged (QTreeWidgetItem *, int)),this, SLOT( onSetSizeMap(QTreeWidgetItem *, int) ) ); - connect( myAttractorCheck, SIGNAL( stateChanged ( int )), this, SLOT( onAttractorClicked( int ) ) ); - connect( myConstSizeCheck, SIGNAL( stateChanged ( int )), this, SLOT( onConstSizeClicked( int ) ) ); - connect( smpTab, SIGNAL( currentChanged ( int )), this, SLOT( onTabChanged( int ) ) ); - connect( myTabWidget, SIGNAL( currentChanged ( int )), this, SLOT( onTabChanged( int ) ) ); + connect( addMapButton, SIGNAL( clicked()), SLOT( onAddMap() ) ); + connect( removeMapButton, SIGNAL( clicked()), SLOT( onRemoveMap() ) ); + connect( modifyMapButton, SIGNAL( clicked()), SLOT( onModifyMap() ) ); + connect( mySizeMapTable, SIGNAL( itemClicked (QTreeWidgetItem *, int)), SLOT( onSmpItemClicked(QTreeWidgetItem *, int) ) ); + connect( myGeomSelWdg2, SIGNAL( contentModified() ), SLOT( onMapGeomContentModified() ) ); + connect( myGeomSelWdg1, SIGNAL( contentModified() ), SLOT( onMapGeomContentModified() ) ); + connect( myAttSelWdg, SIGNAL( contentModified() ), SLOT( onMapGeomContentModified() ) ); + connect( mySizeMapTable, SIGNAL( itemChanged (QTreeWidgetItem *, int)), SLOT( onSetSizeMap(QTreeWidgetItem *, int) ) ); + connect( myAttractorCheck, SIGNAL( stateChanged ( int )), SLOT( onAttractorClicked( int ) ) ); + connect( myConstSizeCheck, SIGNAL( stateChanged ( int )), SLOT( onConstSizeClicked( int ) ) ); + connect( smpTab, SIGNAL( currentChanged ( int )), SLOT( onTabChanged( int ) ) ); + connect( myTabWidget, SIGNAL( currentChanged ( int )), SLOT( onTabChanged( int ) ) ); // Enforced vertices - connect( myEnforcedTreeWidget,SIGNAL( itemClicked(QTreeWidgetItem *, int)), this, SLOT( synchronizeCoords() ) ); - connect( myEnforcedTreeWidget,SIGNAL( itemChanged(QTreeWidgetItem *, int)), this, SLOT( updateEnforcedVertexValues(QTreeWidgetItem *, int) ) ); - connect( myEnforcedTreeWidget,SIGNAL( itemSelectionChanged() ), this, SLOT( synchronizeCoords() ) ); - connect( addVertexButton, SIGNAL( clicked()), this, SLOT( onAddEnforcedVertices() ) ); - connect( removeVertexButton, SIGNAL( clicked()), this, SLOT( onRemoveEnforcedVertex() ) ); - connect( myEnfVertexWdg, SIGNAL( contentModified()), this, SLOT( onSelectEnforcedVertex() ) ); - connect( myInternalEnforcedVerticesAllFaces, SIGNAL( stateChanged ( int )), this, SLOT( onInternalVerticesClicked( int ) ) ); + connect( myEnforcedTreeWidget,SIGNAL( itemClicked(QTreeWidgetItem *, int)), SLOT( synchronizeCoords() ) ); + connect( myEnforcedTreeWidget,SIGNAL( itemChanged(QTreeWidgetItem *, int)), SLOT( updateEnforcedVertexValues(QTreeWidgetItem *, int) ) ); + connect( myEnforcedTreeWidget,SIGNAL( itemSelectionChanged() ), SLOT( synchronizeCoords() ) ); + connect( addVertexButton, SIGNAL( clicked()), SLOT( onAddEnforcedVertices() ) ); + connect( removeVertexButton, SIGNAL( clicked()), SLOT( onRemoveEnforcedVertex() ) ); + connect( myEnfVertexWdg, SIGNAL( contentModified()), SLOT( onSelectEnforcedVertex() ) ); + connect( myInternalEnforcedVerticesAllFaces, SIGNAL( stateChanged ( int )), SLOT( onInternalVerticesClicked( int ) ) ); + + // Enforced mesh + connect( myAddEnfMeshButton, SIGNAL( clicked()), SLOT( onAddEnforcedMesh())); + connect( myRemoveEnfMeshButton, SIGNAL( clicked()), SLOT( onRemoveEnforcedMesh())); + connect( myEnfMeshWdg, SIGNAL( contentModified()), SLOT( onEnforcedMeshSelected())); + connect( myEnfMeshTableWdg, SIGNAL( itemSelectionChanged()), SLOT( onEnfMeshTableSelected())); + // Periodicity - connect( myPeriodicityAddButton, SIGNAL( clicked()), this, SLOT( onAddPeriodicity() ) ); - connect( myPeriodicityRemoveButton, SIGNAL( clicked()), this, SLOT( onRemovePeriodicity() ) ); - connect( myPeriodicityTreeWidget, SIGNAL( itemClicked(QTreeWidgetItem*, int)), this, SLOT( onPeriodicityTreeClicked(QTreeWidgetItem *, int) ) ); - connect( myPeriodicityGroupBox2, SIGNAL(toggled(bool)), this, SLOT(onPeriodicityByVerticesChecked(bool))); + connect( myPeriodicityAddButton, SIGNAL( clicked()), SLOT( onAddPeriodicity() ) ); + connect( myPeriodicityRemoveButton, SIGNAL( clicked()), SLOT( onRemovePeriodicity() ) ); + connect( myPeriodicityTreeWidget, SIGNAL( itemClicked(QTreeWidgetItem*, int)), SLOT( onPeriodicityTreeClicked(QTreeWidgetItem *, int) ) ); + connect( myPeriodicityGroupBox2, SIGNAL(toggled(bool)), SLOT(onPeriodicityByVerticesChecked(bool))); ListOfWidgets::const_iterator anIt = myPeriodicitySelectionWidgets.begin(); for (; anIt != myPeriodicitySelectionWidgets.end(); anIt++) { StdMeshersGUI_ObjectReferenceParamWdg * w1 = ( StdMeshersGUI_ObjectReferenceParamWdg* ) ( *anIt ); - connect( w1, SIGNAL(contentModified ()), this, SLOT(onPeriodicityContentModified())); + connect( w1, SIGNAL( contentModified ()), SLOT( onPeriodicityContentModified() )); } @@ -2025,6 +2089,7 @@ void BLSURFPluginGUI_HypothesisCreator::retrieveParams() const } // Hyper patches + QString patchEntries; for ( int i = 0; i < data.hyperpatches.size(); ++i ) { @@ -2036,6 +2101,18 @@ void BLSURFPluginGUI_HypothesisCreator::retrieveParams() const that->myStdWidget->onPhysicalMeshChanged(); that->myStdWidget->onGeometricMeshChanged(); that->onStateChange(); + + // Enforced mesh + + BLSURFPlugin::BLSURFPlugin_Hypothesis_var h = + BLSURFPlugin::BLSURFPlugin_Hypothesis::_narrow( initParamsHypothesis() ); + + BLSURFPlugin::EnforcedMeshesList_var enfMeshes = h->GetEnforcedMeshes(); + for ( CORBA::ULong i = 0; i < enfMeshes->length(); ++i ) + { + BLSURFPlugin::MG_EnforcedMesh1D & enfMesh = enfMeshes[i]; + that->addEnforcedMesh( enfMesh.mesh.in(), enfMesh.groupName.in() ); + } } /** BLSURFPluginGUI_HypothesisCreator::storeParams() @@ -2589,6 +2666,31 @@ bool BLSURFPluginGUI_HypothesisCreator::storeParamsToHypo( const BlsurfHypothesi h->SetHyperPatches( hpl ); + // Enforced meshes + BLSURFPlugin::EnforcedMeshesList_var enfMeshesList = new BLSURFPlugin::EnforcedMeshesList(); + enfMeshesList->length( myEnfMeshTableWdg->rowCount() ); + + int nbMeshes = 0; + for ( int row = 0, nbRow = myEnfMeshTableWdg->rowCount(); row < nbRow; ++row ) + { + QTableWidgetItem * meshCell = myEnfMeshTableWdg->item( row, 0 ); + QString entry = meshCell->data( Qt::UserRole ).toString(); + QTableWidgetItem * groupCell = myEnfMeshTableWdg->item( row, 1 ); + QString groupName = groupCell->text(); + + SMESH::SMESH_IDSource_var mesh = SMESH::EntryToInterface< SMESH::SMESH_IDSource >( entry ); + if ( !mesh->_is_nil() ) + { + enfMeshesList[ nbMeshes ].mesh = SMESH::SMESH_IDSource::_duplicate( mesh ); + enfMeshesList[ nbMeshes ].groupName = CORBA::string_dup( groupName.toStdString().c_str() ); + ++nbMeshes; + } + } + enfMeshesList->length( nbMeshes ); + + h->SetEnforcedMeshes( enfMeshesList ); + + } // try catch(...) { ok = false; @@ -2898,6 +3000,7 @@ void BLSURFPluginGUI_HypothesisCreator::onTabChanged(int tab) myPeriodicityP1TargetWdg ->deactivateSelection(); myPeriodicityP2TargetWdg ->deactivateSelection(); myPeriodicityP3TargetWdg ->deactivateSelection(); + myEnfMeshWdg ->deactivateSelection(); if ( myHyPatchFaceSelBtn->isChecked() ) myHyPatchFaceSelBtn->toggle(); if ( myHyPatchGroupSelBtn->isChecked() ) @@ -2934,6 +3037,15 @@ void BLSURFPluginGUI_HypothesisCreator::onTabChanged(int tab) mySmpSizeSpin->RangeStepAndValidator(minSize, maxSize, 1.0, "length_precision"); myAttSizeSpin->RangeStepAndValidator(minSize, maxSize, 1.0, "length_precision"); } + + if ( tab == ENF_M_TAB ) + { + myEnfMeshWdg->activateSelection(); + onEnforcedMeshSelected(); // update buttons + onEnfMeshTableSelected(); + if ( myEnforcedGroupName->text().isEmpty() ) + myEnforcedGroupName->setText("Group 1D"); + } } void BLSURFPluginGUI_HypothesisCreator::onAttractorClicked(int state) @@ -3573,6 +3685,153 @@ void BLSURFPluginGUI_HypothesisCreator::onHyPatchRemove() } } +//================================================================================ +/*! + * \brief Add a new row in Enforced mesh table + */ +//================================================================================ + +void BLSURFPluginGUI_HypothesisCreator::addEnforcedMesh( SMESH::SMESH_IDSource_ptr mesh, + const QString& groupName ) +{ + _PTR(SObject) sobj = SMESH::FindSObject( mesh ); + if ( !sobj ) + return; + + QString meshEntry = sobj->GetID().c_str(); + QString meshName = sobj->GetName().c_str(); + + QTableWidgetItem* meshCell = new QTableWidgetItem( meshName ); + meshCell->setData( Qt::UserRole, meshEntry ); + meshCell->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled ); + + QTableWidgetItem* groupCell = new QTableWidgetItem( groupName ); + groupCell->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable ); + + int row = myEnfMeshTableWdg->rowCount(); + myEnfMeshTableWdg->insertRow( row ); + myEnfMeshTableWdg->setItem( row, 0, meshCell ); + myEnfMeshTableWdg->setItem( row, 1, groupCell ); + + myEnfMeshTableWdg->resizeColumnToContents( 0 ); + myEnfMeshTableWdg->resizeColumnToContents( 1 ); +} + +//================================================================================ +/*! + * \brief SLOT called when [Add] is clicked in Enforced mesh tab. + * Add an item to the enforced meshes table + */ +//================================================================================ + +void BLSURFPluginGUI_HypothesisCreator::onAddEnforcedMesh() +{ + if ( myEnfMeshWdg->NbObjects() != 1 ) + return; + + SMESH::SMESH_IDSource_var mesh = myEnfMeshWdg->GetObject< SMESH::SMESH_IDSource >(); + QString groupName = myEnforcedGroupName->text().simplified(); + + addEnforcedMesh( mesh, groupName ); + + selectionMgr()->clearSelected(); + myEnfMeshWdg->SetObject( SMESH::SMESH_IDSource::_nil() ); +} + +//================================================================================ +/*! + * \brief SLOT called when [Remove] is clicked in Enforced mesh tab. + * Remove a selected mesh from the enforced meshes table + */ +//================================================================================ + +void BLSURFPluginGUI_HypothesisCreator::onRemoveEnforcedMesh() +{ + QList selectedRows; + QList selectedItems = myEnfMeshTableWdg->selectedItems(); + QTableWidgetItem* item; + int row; + foreach( item, selectedItems ) + { + row = item->row(); + if (!selectedRows.contains( row ) ) + selectedRows.append(row); + } + + qSort( selectedRows ); + QListIterator it( selectedRows ); + it.toBack(); + while ( it.hasPrevious() ) { + row = it.previous(); + myEnfMeshTableWdg->removeRow(row ); + } + + myEnfMeshTableWdg->selectionModel()->clearSelection(); + + onEnforcedMeshSelected(); // to activate [Add] if possible +} + +//================================================================================ +/*! + * \brief SLOT called when mesh selection changes. Enable/disable [Add] button + */ +//================================================================================ + +void BLSURFPluginGUI_HypothesisCreator::onEnforcedMeshSelected() +{ + bool enable = ( myEnfMeshWdg->NbObjects() == 1 ); + if ( enable ) + { + // check if a selected mesh contains segments + SMESH::SMESH_IDSource_var mesh = myEnfMeshWdg->GetObject< SMESH::SMESH_IDSource >(); + if (( enable = !mesh->_is_nil() )) + { + SMESH::array_of_ElementType_var types = mesh->GetTypes(); + if (( enable = ( types->length() > 0 ))) + { + enable = false; + for ( CORBA::ULong i = 0; i < types->length() && !enable; ++i ) + enable = ( types[ i ] = SMESH::EDGE ); + } + } + + // check if this mesh is already in the table + if ( enable ) + { + _PTR(SObject) sobj = SMESH::FindSObject( mesh ); + if (( enable = bool( sobj ))) + { + QString meshEntry = sobj->GetID().c_str(); + for ( int row = 0, nbRow = myEnfMeshTableWdg->rowCount(); row < nbRow && enable; ++row ) + { + QTableWidgetItem * cell = myEnfMeshTableWdg->item( row, 0 ); + enable = ( meshEntry != cell->data( Qt::UserRole ).toString() ); + } + } + } + } + myAddEnfMeshButton->setEnabled( enable ); +} + +//================================================================================ +/*! + * \brief SLOT called when selection changes in the table. Enable/disable [Remove] button + */ +//================================================================================ + +void BLSURFPluginGUI_HypothesisCreator::onEnfMeshTableSelected() +{ + bool enable = !myEnfMeshTableWdg->selectedItems().empty(); + + myRemoveEnfMeshButton->setEnabled( enable ); +} + +//================================================================================ +/*! + * \brief Return false if algorithm is a re-mesher + */ +//================================================================================ + bool BLSURFPluginGUI_HypothesisCreator::hasGeom() const { return hypType() == BLSURFPlugin_Hypothesis::GetHypType(true); diff --git a/src/GUI/BLSURFPluginGUI_HypothesisCreator.h b/src/GUI/BLSURFPluginGUI_HypothesisCreator.h index 0f5788e..1ae9ef4 100644 --- a/src/GUI/BLSURFPluginGUI_HypothesisCreator.h +++ b/src/GUI/BLSURFPluginGUI_HypothesisCreator.h @@ -242,6 +242,11 @@ protected slots: void onSelectEnforcedVertex(); void clearEnforcedVertexWidgets(); void onInternalVerticesClicked(int); + // Enforced mesh tab + void onAddEnforcedMesh(); + void onRemoveEnforcedMesh(); + void onEnforcedMeshSelected(); + void onEnfMeshTableSelected(); // Periodicity tab void onPeriodicityByVerticesChecked(bool); void onAddPeriodicity(); @@ -274,6 +279,8 @@ private: void addHyPatchToTable(const QString& tags, const QString& entries); bool hasGeom() const; + void addEnforcedMesh( SMESH::SMESH_IDSource_ptr mesh, const QString& groupName ); + private: QTabWidget* myTabWidget; @@ -336,6 +343,17 @@ private: QCheckBox *myInternalEnforcedVerticesAllFaces; QLineEdit *myInternalEnforcedVerticesAllFacesGroup; + + // Enforced meshes + QWidget* myEnfMeshGroup; + StdMeshersGUI_ObjectReferenceParamWdg *myEnfMeshWdg; + QTableWidget* myEnfMeshTableWdg; + QLineEdit* myEnforcedGroupName; + QPushButton* myAddEnfMeshButton; + QPushButton* myRemoveEnfMeshButton; + + + // map = entry , size map QMap mySMPMap; // Map QMap myATTMap; // Map @@ -396,7 +414,7 @@ private: class EnforcedTreeWidgetDelegate : public QItemDelegate { - Q_OBJECT + Q_OBJECT public: EnforcedTreeWidgetDelegate(QObject *parent = 0); @@ -409,7 +427,7 @@ public: const QModelIndex &index) const; void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, - const QModelIndex &index) const; + const QModelIndex &index) const; bool vertexExists(QAbstractItemModel *model, const QModelIndex &index, QString value) const; }; diff --git a/src/GUI/BLSURFPlugin_msg_en.ts b/src/GUI/BLSURFPlugin_msg_en.ts index 9016435..537e927 100644 --- a/src/GUI/BLSURFPlugin_msg_en.ts +++ b/src/GUI/BLSURFPlugin_msg_en.ts @@ -695,6 +695,37 @@ The smaller this distance is, the closer the mesh is to the exact surface (only Hyper-patch + + BLSURFPluginGUI_HypothesisCreator + + ENF_NAME_COLUMN + 1D object + + + ENF_GROUP_COLUMN + Group name + + + ENF_SELECT_MESH + Select 1D object + + + ENF_GROUP_LABEL + Group name + + + ENF_ADD + Add + + + ENF_REMOVE + Remove + + + ENF_MESH + Enforced mesh + + BLSURFPluginGUI_AdvWidget