--- /dev/null
+# Deflection 2D
+
+
+import salome
+salome.salome_init()
+from salome.geom import geomBuilder
+geompy = geomBuilder.New(salome.myStudy)
+
+import SMESH
+from salome.smesh import smeshBuilder
+smesh = smeshBuilder.New(salome.myStudy)
+
+# fuse a box and a sphere
+Sphere_1 = geompy.MakeSphereR(100)
+Box_1 = geompy.MakeBoxDXDYDZ(200, 200, 200)
+Fuse = geompy.MakeFuse( Sphere_1, Box_1, theName="box + sphere" )
+
+# create a mesh
+mesh = smesh.Mesh( Fuse, "Deflection_2D")
+algo = mesh.Segment()
+algo.LocalLength(35)
+algo = mesh.Triangle()
+mesh.Compute()
+
+# get min and max deflection
+minMax = mesh.GetMinMax( SMESH.FT_Deflection2D )
+print "min and max deflection: ", minMax
+
+# get deflection of a certain face
+faceID = mesh.NbEdges() + mesh.NbFaces()
+defl = mesh.FunctorValue( SMESH.FT_Deflection2D, faceID )
+print "deflection of face %s = %s" % ( faceID, defl )
+
+margin = minMax[1] / 2
+
+# get all faces with deflection LESS than the margin
+aFilter = smesh.GetFilter(SMESH.FACE, SMESH.FT_Deflection2D, '<', margin, mesh=mesh)
+anIds = aFilter.GetIDs()
+print "%s faces have deflection less than %s" %( len(anIds), margin )
+
+# create a group of faces with deflection MORE than the margin
+aGroup = mesh.MakeGroup("Deflection > " + `margin`, SMESH.FACE, SMESH.FT_Deflection2D,'>',margin)
+print "%s faces have deflection more than %s: %s ..." %( aGroup.Size(), margin, aGroup.GetIDs()[:10] )
+
+salome.sg.updateObjBrowser(True)
or edit mesh groups, remove elements from the mesh, control
mesh quality by different parameters, etc.
-Several criteria can be combined together by using logical operators \a
-AND and \a OR. In addition, a filter criterion can be reverted
-using logical operator \a NOT.
+Several \ref filtering_criteria "filtering criteria" can be combined
+together by using logical operators \a AND and \a OR. In addition, a
+filter criterion can be reverted using logical operator \a NOT.
-Some filtering criteria use the functionality of \ref quality_page "mesh quality controls"
-to filter mesh nodes / elements by specific characteristic (Area, Length, etc).
+Some filtering criteria use the functionality of \ref quality_page
+"mesh quality controls" to filter mesh nodes / elements by specific
+characteristic (Area, Length, etc).
The functinality of mesh filters is available in both GUI and TUI
modes:
-- In GUI, filters are available in some dialog boxes via
-"Set Filters" button, clicking on which opens the dialog box
+- In GUI, filters are available in some dialog boxes via "Set Filters"
+button, clicking on which opens the \ref filtering_elements "dialog box"
allowing to specify the list of filter criteria to be applied to the
-current selection. See \subpage selection_filter_library_page page to learn more
-about selection filters and their usage in GUI.
+current selection. See \subpage selection_filter_library_page page to
+learn more about selection filters and their usage in GUI.
- In Python scripts, filters can be used to choose only some mesh
entities (nodes or elements) for the operations, which require the
<li>\subpage bare_border_faces_page "Bare border faces"</li>
<li>\subpage over_constrained_faces_page "Over-constrained faces"</li>
<li>\subpage length_2d_page "Length 2D"</li>
+<li>\subpage deflection_2d_page "Deflection 2D"</li>
<li>\subpage borders_at_multi_connection_2d_page "Borders at multi-connection 2D"</li>
<li>\subpage area_page "Area"</li>
<li>\subpage taper_page "Taper"</li>
--- /dev/null
+/*!
+
+\page deflection_2d_page Deflection 2D
+
+\n This quality control criterion consists of calculation of distance
+between a mesh face gravity corner and the surface the face discretizes.
+
+<em>To apply the Deflection 2D quality criterion to your mesh:</em>
+<ol>
+<li>Display your mesh in the viewer. </li>
+
+<li>Choose <b>Controls > Face Controls > Deflection 2D</b> or click
+<em>"Deflection 2D"</em> button in the toolbar.
+
+Your mesh will be displayed in the viewer with faces colored according
+to the applied mesh quality control criterion:
+
+\image html deflection_2d.png
+</li>
+</ol>
+
+<br><b>See Also</b> a sample TUI Script of a
+\ref tui_deflection_2d "Deflection 2D quality control" operation.
+
+*/
\page selection_filter_library_page Selection filter library
+\tableofcontents
+
+\section selection_filter_library Filter library
+
\n Selection filter library allows creating and storing in files
the filters that can be later reused for operations on meshes. You can
access it from the Main Menu via <b>Tools / Selection filter library</b>.
\n In <b>Filter name</b> box you can specify the name for your
filter. By default it is prefixed with the corresponding entity type.
-\anchor filtering_elements
-<h2>Filter Dialog</h2>
+\section filtering_elements Filter Dialog
When we use filters during group creation or another operation (by
clicking <b>Set Filter</b> button in the corresponding dialog), the
is no selected mesh in the Object Browser and the filter can not be
created. You have to select the mesh and the button will be enabled.
+\section filtering_criteria Filtering Criteria
+
Some criteria are applicable to all <b>Entity types</b>:
<ul><li>
<b>Belong to Geom</b> selects entities whose all nodes lie on the
angular tolerance (defined in degrees). Selection continues among all neighbor faces of already
selected ones.<br>
</li><li>
+<b>Deflection 2D</b> selects 2D mesh elements having distance between their gravity
+centers and underlying surfaces, which is more, less or equal (within a given <b>Tolerance</b>) to the predefined <b>Threshold Value</b>. See also a
+\ref deflection_2d_page "Deflection 2D quality control".
+</li><li>
<b>Element Diameter 2D</b> selects triangles and quadrangles composed of the edges and
diagonals with a value of length, which is more, less or equal
(within a given <b>Tolerance</b>) to the predefined <b>Threshold Value</b>. See also a
\section tui_length_2d Length 2D
\tui_script{quality_controls_ex11.py}
+\section tui_deflection_2d Deflection 2D
+\tui_script{quality_controls_defl.py}
+
\section tui_borders_at_multiconnection_2d Borders at Multiconnection 2D
\tui_script{quality_controls_ex12.py}
FT_MultiConnection2D,
FT_Length,
FT_Length2D,
+ FT_Deflection2D,
FT_NodeConnectivityNumber,
FT_BelongToMeshGroup,
FT_BelongToGeom,
typedef sequence<Value> Values;
Values GetValues();
};
+ interface Deflection2D : NumericalFunctor{};
interface MultiConnection : NumericalFunctor{};
interface MultiConnection2D : NumericalFunctor
{
MaxElementLength3D CreateMaxElementLength3D();
Length CreateLength();
Length2D CreateLength2D();
+ Deflection2D CreateDeflection2D();
MultiConnection CreateMultiConnection();
MultiConnection2D CreateMultiConnection2D();
BallDiameter CreateBallDiameter();
* Return point state in a closed 2D mesh in terms of TopAbs_State enumeration.
* TopAbs_UNKNOWN state means that either mesh is wrong or the analysis fails.
*/
- short GetPointState(in double x, in double y, in double z)
+ short GetPointState(in double x, in double y, in double z)
+ raises (SALOME::SALOME_Exception);
+
+ /*!
+ * Check if a 2D mesh is manifold
+ */
+ boolean IsManifold()
+ raises (SALOME::SALOME_Exception);
+
+ /*!
+ * Check if orientation of 2D elements is coherent
+ */
+ boolean IsCoherentOrientation2D()
+ raises (SALOME::SALOME_Exception);
+
+ /*!
+ * Returns all or only closed FreeBorder's.
+ */
+ ListOfFreeBorders FindFreeBorders(in boolean closedOnly)
+ raises (SALOME::SALOME_Exception);
+
+ /*!
+ * Fill with 2D elements a hole defined by a FreeBorder.
+ */
+ void FillHole(in FreeBorder hole)
raises (SALOME::SALOME_Exception);
/*!
mesh_tree_hypo.png
mesh_tree_hypo_segment.png
mesh_tree_hypo_volume.png
+ mesh_tree_hypo_cartesian.png
mesh_tree_mesh.png
mesh_tree_importedmesh.png
mesh_tree_mesh_warn.png
mesh_tree_hypo_source_3d_shape.png
mesh_tree_hypo_projection_3d.png
mesh_tree_hypo_projection_2d.png
+ mesh_tree_hypo_quadratic.png
mesh_build_compound.png
copy_mesh.png
mesh_node_to_point.png
mesh_extmeth_node_offset.png
mesh_extmeth_surf_offset_smooth.png
mesh_extmeth_face_offset.png
+ mesh_quality.png
+ mesh_show.png
+ mesh_hide.png
+ mesh_deflection.png
)
INSTALL(FILES ${SMESH_RESOURCES_FILES} DESTINATION ${SALOME_SMESH_INSTALL_RES_DATA})
label-id ="Quadratic Mesh"
icon-id ="mesh_algo_quad.png"
dim ="1"
- context ="GLOBAL"
auxiliary="true"/>
<hypothesis type ="MaxElementArea"
#include "SMESH_ControlsDef.hxx"
#include "SMDS_BallElement.hxx"
+#include "SMDS_FacePosition.hxx"
#include "SMDS_Iterator.hxx"
#include "SMDS_Mesh.hxx"
#include "SMDS_MeshElement.hxx"
#include <BRepAdaptor_Surface.hxx>
#include <BRepBndLib.hxx>
#include <BRepBuilderAPI_Copy.hxx>
+#include <BRepClass3d_SolidClassifier.hxx>
#include <BRepClass_FaceClassifier.hxx>
#include <BRep_Tool.hxx>
+#include <GeomLib_IsPlanarSurface.hxx>
#include <Geom_CylindricalSurface.hxx>
#include <Geom_Plane.hxx>
#include <Geom_Surface.hxx>
#include <NCollection_Map.hxx>
#include <Precision.hxx>
+#include <ShapeAnalysis_Surface.hxx>
#include <TColStd_MapIteratorOfMapOfInteger.hxx>
#include <TColStd_MapOfInteger.hxx>
#include <TColStd_SequenceOfAsciiString.hxx>
// +-----+------+ +-----+------+
// | | | |
// | | | |
- // result sould be 2 in both cases
+ // result should be 2 in both cases
//
int aResult0 = 0, aResult1 = 0;
// last node, it is a medium one in a quadratic edge
}
if ( anIter ) {
- double xyz[3];
+ SMESH_NodeXYZ p;
while( anIter->more() ) {
- if ( const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( anIter->next() ))
- {
- aNode->GetXYZ( xyz );
- theRes.push_back( gp_XYZ( xyz[0], xyz[1], xyz[2] ));
- }
+ if ( p.Set( anIter->next() ))
+ theRes.push_back( p );
}
}
aVal = Max(aVal,Max(L7,L8));
break;
}
- case SMDSEntity_Quad_Penta: { // quadratic pentas
+ case SMDSEntity_Quad_Penta:
+ /*case SMDSEntity_BiQuad_Penta:*/ { // quadratic pentas
double L1 = getDistance(P( 1 ),P( 7 )) + getDistance(P( 7 ),P( 2 ));
double L2 = getDistance(P( 2 ),P( 8 )) + getDistance(P( 8 ),P( 3 ));
double L3 = getDistance(P( 3 ),P( 9 )) + getDistance(P( 9 ),P( 1 ));
*/
//================================================================================
-double Length2D::GetValue( long theElementId )
+double Length2D::GetValue( const TSequenceOfXYZ& P )
{
- TSequenceOfXYZ P;
-
- if ( GetPoints( theElementId, P ))
- {
- double aVal = 0;
- int len = P.size();
- SMDSAbs_EntityType aType = P.getElementEntity();
+ double aVal = 0;
+ int len = P.size();
+ SMDSAbs_EntityType aType = P.getElementEntity();
- switch (aType) {
- case SMDSEntity_Edge:
- if (len == 2)
- aVal = getDistance( P( 1 ), P( 2 ) );
- break;
- case SMDSEntity_Quad_Edge:
- if (len == 3) // quadratic edge
- aVal = getDistance(P( 1 ),P( 3 )) + getDistance(P( 3 ),P( 2 ));
- break;
- case SMDSEntity_Triangle:
- if (len == 3){ // triangles
- double L1 = getDistance(P( 1 ),P( 2 ));
- double L2 = getDistance(P( 2 ),P( 3 ));
- double L3 = getDistance(P( 3 ),P( 1 ));
- aVal = Min(L1,Min(L2,L3));
- }
- break;
- case SMDSEntity_Quadrangle:
- if (len == 4){ // quadrangles
- double L1 = getDistance(P( 1 ),P( 2 ));
- double L2 = getDistance(P( 2 ),P( 3 ));
- double L3 = getDistance(P( 3 ),P( 4 ));
- double L4 = getDistance(P( 4 ),P( 1 ));
- aVal = Min(Min(L1,L2),Min(L3,L4));
- }
- break;
- case SMDSEntity_Quad_Triangle:
- case SMDSEntity_BiQuad_Triangle:
- if (len >= 6){ // quadratic triangles
- double L1 = getDistance(P( 1 ),P( 2 )) + getDistance(P( 2 ),P( 3 ));
- double L2 = getDistance(P( 3 ),P( 4 )) + getDistance(P( 4 ),P( 5 ));
- double L3 = getDistance(P( 5 ),P( 6 )) + getDistance(P( 6 ),P( 1 ));
- aVal = Min(L1,Min(L2,L3));
- }
- break;
- case SMDSEntity_Quad_Quadrangle:
- case SMDSEntity_BiQuad_Quadrangle:
- if (len >= 8){ // quadratic quadrangles
- double L1 = getDistance(P( 1 ),P( 2 )) + getDistance(P( 2 ),P( 3 ));
- double L2 = getDistance(P( 3 ),P( 4 )) + getDistance(P( 4 ),P( 5 ));
- double L3 = getDistance(P( 5 ),P( 6 )) + getDistance(P( 6 ),P( 7 ));
- double L4 = getDistance(P( 7 ),P( 8 )) + getDistance(P( 8 ),P( 1 ));
- aVal = Min(Min(L1,L2),Min(L3,L4));
- }
- break;
- case SMDSEntity_Tetra:
- if (len == 4){ // tetrahedra
- double L1 = getDistance(P( 1 ),P( 2 ));
- double L2 = getDistance(P( 2 ),P( 3 ));
- double L3 = getDistance(P( 3 ),P( 1 ));
- double L4 = getDistance(P( 1 ),P( 4 ));
- double L5 = getDistance(P( 2 ),P( 4 ));
- double L6 = getDistance(P( 3 ),P( 4 ));
- aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
- }
- break;
- case SMDSEntity_Pyramid:
- if (len == 5){ // piramids
- double L1 = getDistance(P( 1 ),P( 2 ));
- double L2 = getDistance(P( 2 ),P( 3 ));
- double L3 = getDistance(P( 3 ),P( 4 ));
- double L4 = getDistance(P( 4 ),P( 1 ));
- double L5 = getDistance(P( 1 ),P( 5 ));
- double L6 = getDistance(P( 2 ),P( 5 ));
- double L7 = getDistance(P( 3 ),P( 5 ));
- double L8 = getDistance(P( 4 ),P( 5 ));
-
- aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
- aVal = Min(aVal,Min(L7,L8));
- }
- break;
- case SMDSEntity_Penta:
- if (len == 6) { // pentaidres
- double L1 = getDistance(P( 1 ),P( 2 ));
- double L2 = getDistance(P( 2 ),P( 3 ));
- double L3 = getDistance(P( 3 ),P( 1 ));
- double L4 = getDistance(P( 4 ),P( 5 ));
- double L5 = getDistance(P( 5 ),P( 6 ));
- double L6 = getDistance(P( 6 ),P( 4 ));
- double L7 = getDistance(P( 1 ),P( 4 ));
- double L8 = getDistance(P( 2 ),P( 5 ));
- double L9 = getDistance(P( 3 ),P( 6 ));
-
- aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
- aVal = Min(aVal,Min(Min(L7,L8),L9));
- }
- break;
- case SMDSEntity_Hexa:
- if (len == 8){ // hexahedron
- double L1 = getDistance(P( 1 ),P( 2 ));
- double L2 = getDistance(P( 2 ),P( 3 ));
- double L3 = getDistance(P( 3 ),P( 4 ));
- double L4 = getDistance(P( 4 ),P( 1 ));
- double L5 = getDistance(P( 5 ),P( 6 ));
- double L6 = getDistance(P( 6 ),P( 7 ));
- double L7 = getDistance(P( 7 ),P( 8 ));
- double L8 = getDistance(P( 8 ),P( 5 ));
- double L9 = getDistance(P( 1 ),P( 5 ));
- double L10= getDistance(P( 2 ),P( 6 ));
- double L11= getDistance(P( 3 ),P( 7 ));
- double L12= getDistance(P( 4 ),P( 8 ));
-
- aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
- aVal = Min(aVal,Min(Min(L7,L8),Min(L9,L10)));
- aVal = Min(aVal,Min(L11,L12));
- }
- break;
- case SMDSEntity_Quad_Tetra:
- if (len == 10){ // quadratic tetraidrs
- double L1 = getDistance(P( 1 ),P( 5 )) + getDistance(P( 5 ),P( 2 ));
- double L2 = getDistance(P( 2 ),P( 6 )) + getDistance(P( 6 ),P( 3 ));
- double L3 = getDistance(P( 3 ),P( 7 )) + getDistance(P( 7 ),P( 1 ));
- double L4 = getDistance(P( 1 ),P( 8 )) + getDistance(P( 8 ),P( 4 ));
- double L5 = getDistance(P( 2 ),P( 9 )) + getDistance(P( 9 ),P( 4 ));
- double L6 = getDistance(P( 3 ),P( 10 )) + getDistance(P( 10 ),P( 4 ));
- aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
- }
- break;
- case SMDSEntity_Quad_Pyramid:
- if (len == 13){ // quadratic piramids
- double L1 = getDistance(P( 1 ),P( 6 )) + getDistance(P( 6 ),P( 2 ));
- double L2 = getDistance(P( 2 ),P( 7 )) + getDistance(P( 7 ),P( 3 ));
- double L3 = getDistance(P( 3 ),P( 8 )) + getDistance(P( 8 ),P( 4 ));
- double L4 = getDistance(P( 4 ),P( 9 )) + getDistance(P( 9 ),P( 1 ));
- double L5 = getDistance(P( 1 ),P( 10 )) + getDistance(P( 10 ),P( 5 ));
- double L6 = getDistance(P( 2 ),P( 11 )) + getDistance(P( 11 ),P( 5 ));
- double L7 = getDistance(P( 3 ),P( 12 )) + getDistance(P( 12 ),P( 5 ));
- double L8 = getDistance(P( 4 ),P( 13 )) + getDistance(P( 13 ),P( 5 ));
- aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
- aVal = Min(aVal,Min(L7,L8));
- }
- break;
- case SMDSEntity_Quad_Penta:
- if (len == 15){ // quadratic pentaidres
- double L1 = getDistance(P( 1 ),P( 7 )) + getDistance(P( 7 ),P( 2 ));
- double L2 = getDistance(P( 2 ),P( 8 )) + getDistance(P( 8 ),P( 3 ));
- double L3 = getDistance(P( 3 ),P( 9 )) + getDistance(P( 9 ),P( 1 ));
- double L4 = getDistance(P( 4 ),P( 10 )) + getDistance(P( 10 ),P( 5 ));
- double L5 = getDistance(P( 5 ),P( 11 )) + getDistance(P( 11 ),P( 6 ));
- double L6 = getDistance(P( 6 ),P( 12 )) + getDistance(P( 12 ),P( 4 ));
- double L7 = getDistance(P( 1 ),P( 13 )) + getDistance(P( 13 ),P( 4 ));
- double L8 = getDistance(P( 2 ),P( 14 )) + getDistance(P( 14 ),P( 5 ));
- double L9 = getDistance(P( 3 ),P( 15 )) + getDistance(P( 15 ),P( 6 ));
- aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
- aVal = Min(aVal,Min(Min(L7,L8),L9));
- }
- break;
- case SMDSEntity_Quad_Hexa:
- case SMDSEntity_TriQuad_Hexa:
- if (len >= 20) { // quadratic hexaider
- double L1 = getDistance(P( 1 ),P( 9 )) + getDistance(P( 9 ),P( 2 ));
- double L2 = getDistance(P( 2 ),P( 10 )) + getDistance(P( 10 ),P( 3 ));
- double L3 = getDistance(P( 3 ),P( 11 )) + getDistance(P( 11 ),P( 4 ));
- double L4 = getDistance(P( 4 ),P( 12 )) + getDistance(P( 12 ),P( 1 ));
- double L5 = getDistance(P( 5 ),P( 13 )) + getDistance(P( 13 ),P( 6 ));
- double L6 = getDistance(P( 6 ),P( 14 )) + getDistance(P( 14 ),P( 7 ));
- double L7 = getDistance(P( 7 ),P( 15 )) + getDistance(P( 15 ),P( 8 ));
- double L8 = getDistance(P( 8 ),P( 16 )) + getDistance(P( 16 ),P( 5 ));
- double L9 = getDistance(P( 1 ),P( 17 )) + getDistance(P( 17 ),P( 5 ));
- double L10= getDistance(P( 2 ),P( 18 )) + getDistance(P( 18 ),P( 6 ));
- double L11= getDistance(P( 3 ),P( 19 )) + getDistance(P( 19 ),P( 7 ));
- double L12= getDistance(P( 4 ),P( 20 )) + getDistance(P( 20 ),P( 8 ));
- aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
- aVal = Min(aVal,Min(Min(L7,L8),Min(L9,L10)));
- aVal = Min(aVal,Min(L11,L12));
- }
- break;
- case SMDSEntity_Polygon:
- if ( len > 1 ) {
- aVal = getDistance( P(1), P( P.size() ));
- for ( size_t i = 1; i < P.size(); ++i )
- aVal = Min( aVal, getDistance( P( i ), P( i+1 )));
- }
- break;
- case SMDSEntity_Quad_Polygon:
- if ( len > 2 ) {
- aVal = getDistance( P(1), P( P.size() )) + getDistance( P(P.size()), P( P.size()-1 ));
- for ( size_t i = 1; i < P.size()-1; i += 2 )
- aVal = Min( aVal, getDistance( P( i ), P( i+1 )) + getDistance( P( i+1 ), P( i+2 )));
- }
- break;
- case SMDSEntity_Hexagonal_Prism:
- if (len == 12) { // hexagonal prism
- double L1 = getDistance(P( 1 ),P( 2 ));
- double L2 = getDistance(P( 2 ),P( 3 ));
- double L3 = getDistance(P( 3 ),P( 4 ));
- double L4 = getDistance(P( 4 ),P( 5 ));
- double L5 = getDistance(P( 5 ),P( 6 ));
- double L6 = getDistance(P( 6 ),P( 1 ));
-
- double L7 = getDistance(P( 7 ), P( 8 ));
- double L8 = getDistance(P( 8 ), P( 9 ));
- double L9 = getDistance(P( 9 ), P( 10 ));
- double L10= getDistance(P( 10 ),P( 11 ));
- double L11= getDistance(P( 11 ),P( 12 ));
- double L12= getDistance(P( 12 ),P( 7 ));
-
- double L13 = getDistance(P( 1 ),P( 7 ));
- double L14 = getDistance(P( 2 ),P( 8 ));
- double L15 = getDistance(P( 3 ),P( 9 ));
- double L16 = getDistance(P( 4 ),P( 10 ));
- double L17 = getDistance(P( 5 ),P( 11 ));
- double L18 = getDistance(P( 6 ),P( 12 ));
- aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
- aVal = Min(aVal, Min(Min(Min(L7,L8),Min(L9,L10)),Min(L11,L12)));
- aVal = Min(aVal, Min(Min(Min(L13,L14),Min(L15,L16)),Min(L17,L18)));
- }
- break;
- case SMDSEntity_Polyhedra:
- {
+ switch (aType) {
+ case SMDSEntity_Edge:
+ if (len == 2)
+ aVal = getDistance( P( 1 ), P( 2 ) );
+ break;
+ case SMDSEntity_Quad_Edge:
+ if (len == 3) // quadratic edge
+ aVal = getDistance(P( 1 ),P( 3 )) + getDistance(P( 3 ),P( 2 ));
+ break;
+ case SMDSEntity_Triangle:
+ if (len == 3){ // triangles
+ double L1 = getDistance(P( 1 ),P( 2 ));
+ double L2 = getDistance(P( 2 ),P( 3 ));
+ double L3 = getDistance(P( 3 ),P( 1 ));
+ aVal = Min(L1,Min(L2,L3));
}
break;
- default:
- return 0;
+ case SMDSEntity_Quadrangle:
+ if (len == 4){ // quadrangles
+ double L1 = getDistance(P( 1 ),P( 2 ));
+ double L2 = getDistance(P( 2 ),P( 3 ));
+ double L3 = getDistance(P( 3 ),P( 4 ));
+ double L4 = getDistance(P( 4 ),P( 1 ));
+ aVal = Min(Min(L1,L2),Min(L3,L4));
}
+ break;
+ case SMDSEntity_Quad_Triangle:
+ case SMDSEntity_BiQuad_Triangle:
+ if (len >= 6){ // quadratic triangles
+ double L1 = getDistance(P( 1 ),P( 2 )) + getDistance(P( 2 ),P( 3 ));
+ double L2 = getDistance(P( 3 ),P( 4 )) + getDistance(P( 4 ),P( 5 ));
+ double L3 = getDistance(P( 5 ),P( 6 )) + getDistance(P( 6 ),P( 1 ));
+ aVal = Min(L1,Min(L2,L3));
+ }
+ break;
+ case SMDSEntity_Quad_Quadrangle:
+ case SMDSEntity_BiQuad_Quadrangle:
+ if (len >= 8){ // quadratic quadrangles
+ double L1 = getDistance(P( 1 ),P( 2 )) + getDistance(P( 2 ),P( 3 ));
+ double L2 = getDistance(P( 3 ),P( 4 )) + getDistance(P( 4 ),P( 5 ));
+ double L3 = getDistance(P( 5 ),P( 6 )) + getDistance(P( 6 ),P( 7 ));
+ double L4 = getDistance(P( 7 ),P( 8 )) + getDistance(P( 8 ),P( 1 ));
+ aVal = Min(Min(L1,L2),Min(L3,L4));
+ }
+ break;
+ case SMDSEntity_Tetra:
+ if (len == 4){ // tetrahedra
+ double L1 = getDistance(P( 1 ),P( 2 ));
+ double L2 = getDistance(P( 2 ),P( 3 ));
+ double L3 = getDistance(P( 3 ),P( 1 ));
+ double L4 = getDistance(P( 1 ),P( 4 ));
+ double L5 = getDistance(P( 2 ),P( 4 ));
+ double L6 = getDistance(P( 3 ),P( 4 ));
+ aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
+ }
+ break;
+ case SMDSEntity_Pyramid:
+ if (len == 5){ // pyramid
+ double L1 = getDistance(P( 1 ),P( 2 ));
+ double L2 = getDistance(P( 2 ),P( 3 ));
+ double L3 = getDistance(P( 3 ),P( 4 ));
+ double L4 = getDistance(P( 4 ),P( 1 ));
+ double L5 = getDistance(P( 1 ),P( 5 ));
+ double L6 = getDistance(P( 2 ),P( 5 ));
+ double L7 = getDistance(P( 3 ),P( 5 ));
+ double L8 = getDistance(P( 4 ),P( 5 ));
- if (aVal < 0 ) {
- return 0.;
+ aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
+ aVal = Min(aVal,Min(L7,L8));
}
+ break;
+ case SMDSEntity_Penta:
+ if (len == 6) { // pentahedron
+ double L1 = getDistance(P( 1 ),P( 2 ));
+ double L2 = getDistance(P( 2 ),P( 3 ));
+ double L3 = getDistance(P( 3 ),P( 1 ));
+ double L4 = getDistance(P( 4 ),P( 5 ));
+ double L5 = getDistance(P( 5 ),P( 6 ));
+ double L6 = getDistance(P( 6 ),P( 4 ));
+ double L7 = getDistance(P( 1 ),P( 4 ));
+ double L8 = getDistance(P( 2 ),P( 5 ));
+ double L9 = getDistance(P( 3 ),P( 6 ));
- if ( myPrecision >= 0 )
- {
- double prec = pow( 10., (double)( myPrecision ) );
- aVal = floor( aVal * prec + 0.5 ) / prec;
+ aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
+ aVal = Min(aVal,Min(Min(L7,L8),L9));
}
+ break;
+ case SMDSEntity_Hexa:
+ if (len == 8){ // hexahedron
+ double L1 = getDistance(P( 1 ),P( 2 ));
+ double L2 = getDistance(P( 2 ),P( 3 ));
+ double L3 = getDistance(P( 3 ),P( 4 ));
+ double L4 = getDistance(P( 4 ),P( 1 ));
+ double L5 = getDistance(P( 5 ),P( 6 ));
+ double L6 = getDistance(P( 6 ),P( 7 ));
+ double L7 = getDistance(P( 7 ),P( 8 ));
+ double L8 = getDistance(P( 8 ),P( 5 ));
+ double L9 = getDistance(P( 1 ),P( 5 ));
+ double L10= getDistance(P( 2 ),P( 6 ));
+ double L11= getDistance(P( 3 ),P( 7 ));
+ double L12= getDistance(P( 4 ),P( 8 ));
- return aVal;
+ aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
+ aVal = Min(aVal,Min(Min(L7,L8),Min(L9,L10)));
+ aVal = Min(aVal,Min(L11,L12));
+ }
+ break;
+ case SMDSEntity_Quad_Tetra:
+ if (len == 10){ // quadratic tetrahedron
+ double L1 = getDistance(P( 1 ),P( 5 )) + getDistance(P( 5 ),P( 2 ));
+ double L2 = getDistance(P( 2 ),P( 6 )) + getDistance(P( 6 ),P( 3 ));
+ double L3 = getDistance(P( 3 ),P( 7 )) + getDistance(P( 7 ),P( 1 ));
+ double L4 = getDistance(P( 1 ),P( 8 )) + getDistance(P( 8 ),P( 4 ));
+ double L5 = getDistance(P( 2 ),P( 9 )) + getDistance(P( 9 ),P( 4 ));
+ double L6 = getDistance(P( 3 ),P( 10 )) + getDistance(P( 10 ),P( 4 ));
+ aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
+ }
+ break;
+ case SMDSEntity_Quad_Pyramid:
+ if (len == 13){ // quadratic pyramid
+ double L1 = getDistance(P( 1 ),P( 6 )) + getDistance(P( 6 ),P( 2 ));
+ double L2 = getDistance(P( 2 ),P( 7 )) + getDistance(P( 7 ),P( 3 ));
+ double L3 = getDistance(P( 3 ),P( 8 )) + getDistance(P( 8 ),P( 4 ));
+ double L4 = getDistance(P( 4 ),P( 9 )) + getDistance(P( 9 ),P( 1 ));
+ double L5 = getDistance(P( 1 ),P( 10 )) + getDistance(P( 10 ),P( 5 ));
+ double L6 = getDistance(P( 2 ),P( 11 )) + getDistance(P( 11 ),P( 5 ));
+ double L7 = getDistance(P( 3 ),P( 12 )) + getDistance(P( 12 ),P( 5 ));
+ double L8 = getDistance(P( 4 ),P( 13 )) + getDistance(P( 13 ),P( 5 ));
+ aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
+ aVal = Min(aVal,Min(L7,L8));
+ }
+ break;
+ case SMDSEntity_Quad_Penta:
+ //case SMDSEntity_BiQuad_Penta:
+ if (len >= 15){ // quadratic pentahedron
+ double L1 = getDistance(P( 1 ),P( 7 )) + getDistance(P( 7 ),P( 2 ));
+ double L2 = getDistance(P( 2 ),P( 8 )) + getDistance(P( 8 ),P( 3 ));
+ double L3 = getDistance(P( 3 ),P( 9 )) + getDistance(P( 9 ),P( 1 ));
+ double L4 = getDistance(P( 4 ),P( 10 )) + getDistance(P( 10 ),P( 5 ));
+ double L5 = getDistance(P( 5 ),P( 11 )) + getDistance(P( 11 ),P( 6 ));
+ double L6 = getDistance(P( 6 ),P( 12 )) + getDistance(P( 12 ),P( 4 ));
+ double L7 = getDistance(P( 1 ),P( 13 )) + getDistance(P( 13 ),P( 4 ));
+ double L8 = getDistance(P( 2 ),P( 14 )) + getDistance(P( 14 ),P( 5 ));
+ double L9 = getDistance(P( 3 ),P( 15 )) + getDistance(P( 15 ),P( 6 ));
+ aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
+ aVal = Min(aVal,Min(Min(L7,L8),L9));
+ }
+ break;
+ case SMDSEntity_Quad_Hexa:
+ case SMDSEntity_TriQuad_Hexa:
+ if (len >= 20) { // quadratic hexahedron
+ double L1 = getDistance(P( 1 ),P( 9 )) + getDistance(P( 9 ),P( 2 ));
+ double L2 = getDistance(P( 2 ),P( 10 )) + getDistance(P( 10 ),P( 3 ));
+ double L3 = getDistance(P( 3 ),P( 11 )) + getDistance(P( 11 ),P( 4 ));
+ double L4 = getDistance(P( 4 ),P( 12 )) + getDistance(P( 12 ),P( 1 ));
+ double L5 = getDistance(P( 5 ),P( 13 )) + getDistance(P( 13 ),P( 6 ));
+ double L6 = getDistance(P( 6 ),P( 14 )) + getDistance(P( 14 ),P( 7 ));
+ double L7 = getDistance(P( 7 ),P( 15 )) + getDistance(P( 15 ),P( 8 ));
+ double L8 = getDistance(P( 8 ),P( 16 )) + getDistance(P( 16 ),P( 5 ));
+ double L9 = getDistance(P( 1 ),P( 17 )) + getDistance(P( 17 ),P( 5 ));
+ double L10= getDistance(P( 2 ),P( 18 )) + getDistance(P( 18 ),P( 6 ));
+ double L11= getDistance(P( 3 ),P( 19 )) + getDistance(P( 19 ),P( 7 ));
+ double L12= getDistance(P( 4 ),P( 20 )) + getDistance(P( 20 ),P( 8 ));
+ aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
+ aVal = Min(aVal,Min(Min(L7,L8),Min(L9,L10)));
+ aVal = Min(aVal,Min(L11,L12));
+ }
+ break;
+ case SMDSEntity_Polygon:
+ if ( len > 1 ) {
+ aVal = getDistance( P(1), P( P.size() ));
+ for ( size_t i = 1; i < P.size(); ++i )
+ aVal = Min( aVal, getDistance( P( i ), P( i+1 )));
+ }
+ break;
+ case SMDSEntity_Quad_Polygon:
+ if ( len > 2 ) {
+ aVal = getDistance( P(1), P( P.size() )) + getDistance( P(P.size()), P( P.size()-1 ));
+ for ( size_t i = 1; i < P.size()-1; i += 2 )
+ aVal = Min( aVal, getDistance( P( i ), P( i+1 )) + getDistance( P( i+1 ), P( i+2 )));
+ }
+ break;
+ case SMDSEntity_Hexagonal_Prism:
+ if (len == 12) { // hexagonal prism
+ double L1 = getDistance(P( 1 ),P( 2 ));
+ double L2 = getDistance(P( 2 ),P( 3 ));
+ double L3 = getDistance(P( 3 ),P( 4 ));
+ double L4 = getDistance(P( 4 ),P( 5 ));
+ double L5 = getDistance(P( 5 ),P( 6 ));
+ double L6 = getDistance(P( 6 ),P( 1 ));
+
+ double L7 = getDistance(P( 7 ), P( 8 ));
+ double L8 = getDistance(P( 8 ), P( 9 ));
+ double L9 = getDistance(P( 9 ), P( 10 ));
+ double L10= getDistance(P( 10 ),P( 11 ));
+ double L11= getDistance(P( 11 ),P( 12 ));
+ double L12= getDistance(P( 12 ),P( 7 ));
+
+ double L13 = getDistance(P( 1 ),P( 7 ));
+ double L14 = getDistance(P( 2 ),P( 8 ));
+ double L15 = getDistance(P( 3 ),P( 9 ));
+ double L16 = getDistance(P( 4 ),P( 10 ));
+ double L17 = getDistance(P( 5 ),P( 11 ));
+ double L18 = getDistance(P( 6 ),P( 12 ));
+ aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
+ aVal = Min(aVal, Min(Min(Min(L7,L8),Min(L9,L10)),Min(L11,L12)));
+ aVal = Min(aVal, Min(Min(Min(L13,L14),Min(L15,L16)),Min(L17,L18)));
+ }
+ break;
+ case SMDSEntity_Polyhedra:
+ {
+ }
+ break;
+ default:
+ return 0;
+ }
+ if (aVal < 0 ) {
+ return 0.;
}
- return 0.;
+
+ if ( myPrecision >= 0 )
+ {
+ double prec = pow( 10., (double)( myPrecision ) );
+ aVal = floor( aVal * prec + 0.5 ) / prec;
+ }
+
+ return aVal;
}
double Length2D::GetBadRate( double Value, int /*nbNodes*/ ) const
}
}
+//================================================================================
+/*
+ Class : Deflection2D
+ Description : Functor for calculating number of faces conneted to the edge
+*/
+//================================================================================
+
+double Deflection2D::GetValue( const TSequenceOfXYZ& P )
+{
+ if ( myMesh && P.getElement() )
+ {
+ // get underlying surface
+ if ( myShapeIndex != P.getElement()->getshapeId() )
+ {
+ mySurface.Nullify();
+ myShapeIndex = P.getElement()->getshapeId();
+ const TopoDS_Shape& S =
+ static_cast< const SMESHDS_Mesh* >( myMesh )->IndexToShape( myShapeIndex );
+ if ( !S.IsNull() && S.ShapeType() == TopAbs_FACE )
+ {
+ mySurface = new ShapeAnalysis_Surface( BRep_Tool::Surface( TopoDS::Face( S )));
+
+ GeomLib_IsPlanarSurface isPlaneCheck( mySurface->Surface() );
+ if ( isPlaneCheck.IsPlanar() )
+ myPlane.reset( new gp_Pln( isPlaneCheck.Plan() ));
+ else
+ myPlane.reset();
+ }
+ }
+ // project gravity center to the surface
+ if ( !mySurface.IsNull() )
+ {
+ gp_XYZ gc(0,0,0);
+ gp_XY uv(0,0);
+ int nbUV = 0;
+ for ( size_t i = 0; i < P.size(); ++i )
+ {
+ gc += P(i+1);
+
+ if ( const SMDS_FacePosition* fPos = dynamic_cast<const SMDS_FacePosition*>
+ ( P.getElement()->GetNode( i )->GetPosition() ))
+ {
+ uv.ChangeCoord(1) += fPos->GetUParameter();
+ uv.ChangeCoord(2) += fPos->GetVParameter();
+ ++nbUV;
+ }
+ }
+ gc /= P.size();
+ if ( nbUV ) uv /= nbUV;
+
+ double maxLen = MaxElementLength2D().GetValue( P );
+ double tol = 1e-3 * maxLen;
+ double dist;
+ if ( myPlane )
+ {
+ dist = myPlane->Distance( gc );
+ if ( dist < tol )
+ dist = 0;
+ }
+ else
+ {
+ if ( uv.X() != 0 && uv.Y() != 0 ) // faster way
+ mySurface->NextValueOfUV( uv, gc, tol, 0.5 * maxLen );
+ else
+ mySurface->ValueOfUV( gc, tol );
+ dist = mySurface->Gap();
+ }
+ return Round( dist );
+ }
+ }
+ return 0;
+}
+
+void Deflection2D::SetMesh( const SMDS_Mesh* theMesh )
+{
+ NumericalFunctor::SetMesh( dynamic_cast<const SMESHDS_Mesh* >( theMesh ));
+ myShapeIndex = -100;
+ myPlane.reset();
+}
+
+SMDSAbs_ElementType Deflection2D::GetType() const
+{
+ return SMDSAbs_Face;
+}
+
+double Deflection2D::GetBadRate( double Value, int /*nbNodes*/ ) const
+{
+ // meaningless as it is not quality control functor
+ return Value;
+}
+
//================================================================================
/*
Class : MultiConnection
for ( ; volItr != volEnd; ++volItr )
if ( (*volItr).second >= nbNode )
nbVol++;
- // face is not free if number of volumes constructed on thier nodes more than one
+ // face is not free if number of volumes constructed on their nodes more than one
return (nbVol < 2);
}
//================================================================================
/*
Class : GroupColor
- Description : Functor for check color of group to whic mesh element belongs to
+ Description : Functor for check color of group to which mesh element belongs to
*/
//================================================================================
if ( shapeChanges )
{
+ // find most complex shapes
TopTools_IndexedMapOfShape shapesMap;
TopAbs_ShapeEnum shapeTypes[4] = { TopAbs_SOLID, TopAbs_FACE, TopAbs_EDGE, TopAbs_VERTEX };
TopExp_Explorer sub;
bool ElementsOnShape::IsSatisfy( long elemId )
{
- const SMDS_Mesh* mesh = myMeshModifTracer.GetMesh();
- const SMDS_MeshElement* elem =
- ( myType == SMDSAbs_Node ? mesh->FindNode( elemId ) : mesh->FindElement( elemId ));
- if ( !elem || myClassifiers.empty() )
+ if ( myClassifiers.empty() )
+ return false;
+
+ const SMDS_Mesh* mesh = myMeshModifTracer.GetMesh();
+ if ( myType == SMDSAbs_Node )
+ return IsSatisfy( mesh->FindNode( elemId ));
+ return IsSatisfy( mesh->FindElement( elemId ));
+}
+
+bool ElementsOnShape::IsSatisfy (const SMDS_MeshElement* elem)
+{
+ if ( !elem )
return false;
bool isSatisfy = myAllNodesFlag, isNodeOut;
return isSatisfy;
}
+bool ElementsOnShape::IsSatisfy (const SMDS_MeshNode* node,
+ TopoDS_Shape* okShape)
+{
+ if ( !node )
+ return false;
+
+ if ( !myOctree && myClassifiers.size() > 5 )
+ {
+ myWorkClassifiers.resize( myClassifiers.size() );
+ for ( size_t i = 0; i < myClassifiers.size(); ++i )
+ myWorkClassifiers[ i ] = & myClassifiers[ i ];
+ myOctree = new OctreeClassifier( myWorkClassifiers );
+ }
+
+ bool isNodeOut = true;
+
+ if ( okShape || !getNodeIsOut( node, isNodeOut ))
+ {
+ SMESH_NodeXYZ aPnt = node;
+ if ( myOctree )
+ {
+ myWorkClassifiers.clear();
+ myOctree->GetClassifiersAtPoint( aPnt, myWorkClassifiers );
+
+ for ( size_t i = 0; i < myWorkClassifiers.size(); ++i )
+ myWorkClassifiers[i]->SetChecked( false );
+
+ for ( size_t i = 0; i < myWorkClassifiers.size(); ++i )
+ if ( !myWorkClassifiers[i]->IsChecked() &&
+ !myWorkClassifiers[i]->IsOut( aPnt ))
+ {
+ isNodeOut = false;
+ if ( okShape )
+ *okShape = myWorkClassifiers[i]->Shape();
+ break;
+ }
+ }
+ else
+ {
+ for ( size_t i = 0; i < myClassifiers.size(); ++i )
+ if ( !myClassifiers[i].IsOut( aPnt ))
+ {
+ isNodeOut = false;
+ if ( okShape )
+ *okShape = myWorkClassifiers[i]->Shape();
+ break;
+ }
+ }
+ setNodeIsOut( node, isNodeOut );
+ }
+
+ return !isNodeOut;
+}
+
void ElementsOnShape::Classifier::Init( const TopoDS_Shape& theShape,
double theTol,
const Bnd_B3d* theBox )
if ( myProjFace.IsDone() && myProjFace.LowerDistance() <= myTol )
{
// check relatively to the face
- Quantity_Parameter u, v;
+ Standard_Real u, v;
myProjFace.LowerDistanceParameters(u, v);
gp_Pnt2d aProjPnt (u, v);
BRepClass_FaceClassifier aClsf ( TopoDS::Face( myShape ), aProjPnt, myTol );
#include "SMESH_TypeDefs.hxx"
-#include <BRepClass3d_SolidClassifier.hxx>
#include <Bnd_B3d.hxx>
#include <GeomAPI_ProjectPointOnCurve.hxx>
#include <GeomAPI_ProjectPointOnSurf.hxx>
class SMESHDS_SubMesh;
class SMESHDS_GroupBase;
+class BRepClass3d_SolidClassifier;
+class ShapeAnalysis_Surface;
+class gp_Pln;
class gp_Pnt;
namespace SMESH{
*/
class SMESHCONTROLS_EXPORT Length2D: public virtual NumericalFunctor{
public:
- virtual double GetValue( long theElementId );
+ virtual double GetValue( const TSequenceOfXYZ& thePoints );
virtual double GetBadRate( double Value, int nbNodes ) const;
virtual SMDSAbs_ElementType GetType() const;
struct Value{
};
typedef boost::shared_ptr<Length2D> Length2DPtr;
+ /*
+ Class : Deflection2D
+ Description : Functor for calculating distance between a face and geometry
+ */
+ class SMESHCONTROLS_EXPORT Deflection2D: public virtual NumericalFunctor{
+ public:
+ virtual void SetMesh( const SMDS_Mesh* theMesh );
+ virtual double GetValue( const TSequenceOfXYZ& thePoints );
+ virtual double GetBadRate( double Value, int nbNodes ) const;
+ virtual SMDSAbs_ElementType GetType() const;
+ private:
+ Handle(ShapeAnalysis_Surface) mySurface;
+ int myShapeIndex;
+ boost::shared_ptr<gp_Pln> myPlane;
+ };
+
/*
Class : MultiConnection
Description : Functor for calculating number of faces connected to the edge
bool GetAllNodes() const { return myAllNodesFlag; }
void SetShape (const TopoDS_Shape& theShape,
const SMDSAbs_ElementType theType);
+ bool IsSatisfy (const SMDS_MeshElement* elem);
+ bool IsSatisfy (const SMDS_MeshNode* node, TopoDS_Shape* okShape=0);
private:
/*
Class : GroupColor
- Description : Functor for check color of group to whic mesh element belongs to
+ Description : Functor for check color of group to which mesh element belongs to
*/
class SMESHCONTROLS_EXPORT GroupColor: public virtual Predicate{
public:
break;
}
case eLength2D:
- {
myFunctor.reset(new SMESH::Controls::Length2D());
myControlActor = my2DActor;
break;
- }
case eFreeBorders:
myFunctor.reset(new SMESH::Controls::FreeBorders());
myControlActor = my1DActor;
myControlActor = my3DActor;
break;
}
+ case eDeflection2D:
+ {
+ SMESH::Controls::Deflection2D* aControl = new SMESH::Controls::Deflection2D();
+ aControl->SetPrecision( myControlsPrecision );
+ myFunctor.reset( aControl );
+ myControlActor = my2DActor;
+ break;
+ }
case eBareBorderVolume:
{
myFunctor.reset(new SMESH::Controls::BareBorderVolume());
virtual void SetFacesOrientation3DVectors(bool theState) = 0;
virtual bool GetFacesOrientation3DVectors() = 0;
- enum eControl{eNone, eLength, eLength2D, eFreeBorders, eFreeEdges, eFreeNodes,
+ enum eControl{eNone, eLength, eLength2D, eDeflection2D, eFreeBorders, eFreeEdges, eFreeNodes,
eFreeFaces, eMultiConnection, eArea, eTaper, eAspectRatio,
eMinimumAngle, eWarping, eSkew, eAspectRatio3D, eMultiConnection2D, eVolume3D,
eMaxElementLength2D, eMaxElementLength3D, eBareBorderFace, eBareBorderVolume,
//vtkDebugLeaks::SetExitError(0);
}
+namespace
+{
+ // a structure used to nullify SMESH_Gen field of SMESH_Hypothesis,
+ // which is needed for SMESH_Hypothesis not deleted before ~SMESH_Gen()
+ struct _Hyp : public SMESH_Hypothesis
+ {
+ void NullifyGen()
+ {
+ _gen = 0;
+ }
+ };
+}
+
//=============================================================================
/*!
* Destructor
std::map < int, StudyContextStruct * >::iterator i_sc = _mapStudyContext.begin();
for ( ; i_sc != _mapStudyContext.end(); ++i_sc )
{
- delete i_sc->second->myDocument;
- delete i_sc->second;
- }
+ StudyContextStruct* context = i_sc->second;
+ std::map < int, SMESH_Hypothesis * >::iterator i_hyp = context->mapHypothesis.begin();
+ for ( ; i_hyp != context->mapHypothesis.end(); ++i_hyp )
+ {
+ if ( _Hyp* h = static_cast< _Hyp*>( i_hyp->second ))
+ h->NullifyGen();
+ }
+ delete context->myDocument;
+ delete context;
+ }
}
//=============================================================================
// one face only.
SMESH_subMesh::compute_event computeEvent =
aShapeOnly ? SMESH_subMesh::COMPUTE_SUBMESH : SMESH_subMesh::COMPUTE;
+ if ( !aMesh.HasShapeToMesh() )
+ computeEvent = SMESH_subMesh::COMPUTE_NOGEOM; // if several algos and no geometry
if ( anUpward ) // is called from the below code in this method
{
ret = Evaluate( aMesh, aShape, aResMap, /*anUpward=*/true, aShapesId );
}
- MESSAGE( "VSR - SMESH_Gen::Evaluate() finished, OK = " << ret);
return ret;
}
SMESH_Mesh& aMesh = *aSubMesh->GetFather();
SMESH_HypoFilter filter( SMESH_HypoFilter::IsAlgo() );
- filter.And( filter.IsApplicableTo( aShape ));
+ if ( aMesh.HasShapeToMesh() )
+ filter.And( filter.IsApplicableTo( aShape ));
typedef SMESH_Algo::Features AlgoData;
//=============================================================================
/*!
- * Genarate a new id unique withing this Gen
+ * Genarate a new id unique within this Gen
*/
//=============================================================================
using namespace std;
+#ifdef _DEBUG_
+// enable printing algo + shape id + hypo used while meshing
+//#define PRINT_WHO_COMPUTE_WHAT
+#endif
+
//=============================================================================
/*!
* \brief Allocate some memory at construction and release it at destruction.
//=======================================================================
//function : CanAddHypothesis
//purpose : return true if theHypothesis can be attached to me:
-// its dimention is checked
+// its dimension is checked
//=======================================================================
bool SMESH_subMesh::CanAddHypothesis(const SMESH_Hypothesis* theHypothesis) const
//=======================================================================
//function : IsApplicableHypotesis
-//purpose :
+//purpose : check if this sub-mesh can be computed using a hypothesis
+//=======================================================================
+
+bool SMESH_subMesh::IsApplicableHypotesis(const SMESH_Hypothesis* theHypothesis) const
+{
+ if ( !_father->HasShapeToMesh() && _subShape.ShapeType() == TopAbs_SOLID )
+ return true; // true for the PseudoShape
+
+ return IsApplicableHypotesis( theHypothesis, _subShape.ShapeType() );
+}
+
+//=======================================================================
+//function : IsApplicableHypotesis
+//purpose : compare shape type and hypothesis type
//=======================================================================
bool SMESH_subMesh::IsApplicableHypotesis(const SMESH_Hypothesis* theHypothesis,
filter.Or( SMESH_HypoFilter::HasType( algo->GetType()+1 ));
filter.Or( SMESH_HypoFilter::HasType( algo->GetType()+2 ));
if ( SMESH_Algo * curAlgo = (SMESH_Algo*)_father->GetHypothesis( this, filter, true ))
- if ( !curAlgo->NeedDiscreteBoundary() )
+ if ( !curAlgo->NeedDiscreteBoundary() && curAlgo != anHyp )
algoRequiringCleaning = curAlgo;
}
}
_computeState = READY_TO_COMPUTE;
}
break;
+
+ case COMPUTE_NOGEOM: // no geometry; can be several algos
+ if ( !_father->HasShapeToMesh() )
+ {
+ algo = GetAlgo(); // current algo
+ if ( algo )
+ {
+ // apply algos in the order of increasing dimension
+ std::list< const SMESHDS_Hypothesis * > algos = _father->GetHypothesisList( _subShape );
+ for ( int t = SMESHDS_Hypothesis::ALGO_1D; t <= SMESHDS_Hypothesis::ALGO_3D; ++t )
+ {
+ std::list<const SMESHDS_Hypothesis *>::iterator al = algos.begin();
+ for ( ; al != algos.end(); ++al )
+ if ( (*al)->GetType() == t )
+ {
+ _algo = (SMESH_Algo*) *al;
+ _computeState = READY_TO_COMPUTE;
+ if ( !ComputeStateEngine( COMPUTE ))
+ break;
+ }
+ }
+ _algo = algo; // restore
+ }
+ break;
+ }
case COMPUTE:
case COMPUTE_SUBMESH:
{
!algo->isDegenerated( TopoDS::Edge( subS.Current() ))))
ret = false;
}
+#ifdef PRINT_WHO_COMPUTE_WHAT
+ for (subS.ReInit(); subS.More(); subS.Next())
+ {
+ const std::list <const SMESHDS_Hypothesis *> & hyps =
+ _algo->GetUsedHypothesis( *_father, _subShape );
+ SMESH_Comment hypStr;
+ if ( !hyps.empty() )
+ {
+ hypStr << hyps.front()->GetName() << " ";
+ ((SMESHDS_Hypothesis*)hyps.front())->SaveTo( hypStr.Stream() );
+ hypStr << " ";
+ }
+ cout << _algo->GetName()
+ << " " << _father->GetSubMesh( subS.Current() )->GetId()
+ << " " << hypStr << endl;
+ }
+#endif
// Set _computeError
if ( !ret && !isComputeErrorSet )
{
case COMPUTE_CANCELED: // nothing to do
break;
case CLEAN:
- cleanDependants(); // clean sub-meshes, dependant on this one, with event CLEAN
+ cleanDependants(); // clean sub-meshes, dependent on this one, with event CLEAN
removeSubMeshElementsAndNodes();
_computeState = NOT_READY;
if ( _algoState == HYP_OK )
SMESH_Hypothesis::Hypothesis_Status
SMESH_subMesh::CheckConcurentHypothesis (const int theHypType)
{
- MESSAGE ("SMESH_subMesh::CheckConcurentHypothesis");
-
// is there local hypothesis on me?
if ( getSimilarAttached( _subShape, 0, theHypType ) )
return SMESH_Hypothesis::HYP_OK;
//================================================================================
/*!
- * \brief Notify stored event listeners on the occured event
+ * \brief Notify stored event listeners on the occurred event
* \param event - algo_event or compute_event itself
* \param eventType - algo_event or compute_event
* \param hyp - hypothesis, if eventType is algo_event
* \brief Do something on a certain event
* \param event - algo_event or compute_event itself
* \param eventType - algo_event or compute_event
- * \param subMesh - the submesh where the event occures
+ * \param subMesh - the submesh where the event occurs
* \param data - listener data stored in the subMesh
* \param hyp - hypothesis, if eventType is algo_event
*
};
enum compute_event
{
- MODIF_ALGO_STATE, COMPUTE, COMPUTE_SUBMESH, COMPUTE_CANCELED,
+ MODIF_ALGO_STATE, COMPUTE, COMPUTE_SUBMESH, COMPUTE_NOGEOM, COMPUTE_CANCELED,
CLEAN, SUBMESH_COMPUTED, SUBMESH_RESTORED, SUBMESH_LOADED,
MESH_ENTITY_REMOVED, CHECK_COMPUTE_STATE
};
void setEventListener(EventListener* listener, EventListenerData* data);
/*!
- * \brief Notify stored event listeners on the occured event
+ * \brief Notify stored event listeners on the occurred event
* \param event - algo_event or compute_event itself
* \param eventType - algo_event or compute_event
* \param hyp - hypothesis, if eventType is algo_event
bool CanAddHypothesis(const SMESH_Hypothesis* theHypothesis) const;
// return true if theHypothesis can be attached to me:
- // its dimention is checked
+ // its dimension is checked
static bool IsApplicableHypotesis(const SMESH_Hypothesis* theHypothesis,
const TopAbs_ShapeEnum theShapeType);
- bool IsApplicableHypotesis(const SMESH_Hypothesis* theHypothesis) const
- { return IsApplicableHypotesis( theHypothesis, _subShape.ShapeType() ); }
+ bool IsApplicableHypotesis(const SMESH_Hypothesis* theHypothesis) const;
// return true if theHypothesis can be used to mesh me:
// its shape type is checked
type = QObject::tr( "LENGTH_EDGES" );
else if ( dynamic_cast< SMESH::Controls::Length2D* >( f.get() ) )
type = QObject::tr( "LENGTH2D_EDGES" );
+ else if ( dynamic_cast< SMESH::Controls::Deflection2D* >( f.get() ) )
+ type = QObject::tr( "DEFLECTION2D_FACES" );
else if ( dynamic_cast< SMESH::Controls::MultiConnection* >( f.get() ) )
type = QObject::tr( "MULTI_BORDERS" );
else if ( dynamic_cast< SMESH::Controls::MultiConnection2D* >( f.get() ) )
ActionControl.Bind( SMESHOp::OpBareBorderFace, SMESH_Actor::eBareBorderFace );
ActionControl.Bind( SMESHOp::OpOverConstrainedFace, SMESH_Actor::eOverConstrainedFace );
ActionControl.Bind( SMESHOp::OpLength2D, SMESH_Actor::eLength2D );
+ ActionControl.Bind( SMESHOp::OpDeflection2D, SMESH_Actor::eDeflection2D );
ActionControl.Bind( SMESHOp::OpConnection2D, SMESH_Actor::eMultiConnection2D );
ActionControl.Bind( SMESHOp::OpArea, SMESH_Actor::eArea );
ActionControl.Bind( SMESHOp::OpTaper, SMESH_Actor::eTaper );
case SMESHOp::OpBareBorderFace:
case SMESHOp::OpOverConstrainedFace:
case SMESHOp::OpLength2D:
+ case SMESHOp::OpDeflection2D:
case SMESHOp::OpConnection2D:
case SMESHOp::OpArea:
case SMESHOp::OpTaper:
createSMESHAction( SMESHOp::OpBareBorderFace, "BARE_BORDER_FACE", "ICON_BARE_BORDER_FACE", 0, true );
createSMESHAction( SMESHOp::OpOverConstrainedFace, "OVER_CONSTRAINED_FACE", "ICON_OVER_CONSTRAINED_FACE", 0, true );
createSMESHAction( SMESHOp::OpLength2D, "LENGTH_2D", "ICON_LENGTH_2D", 0, true );
+ createSMESHAction( SMESHOp::OpDeflection2D, "DEFLECTION_2D", "ICON_DEFLECTION_2D", 0, true );
createSMESHAction( SMESHOp::OpConnection2D, "CONNECTION_2D", "ICON_CONNECTION_2D", 0, true );
createSMESHAction( SMESHOp::OpArea, "AREA", "ICON_AREA", 0, true );
createSMESHAction( SMESHOp::OpTaper, "TAPER", "ICON_TAPER", 0, true );
<< SMESHOp::OpNodeConnectivityNb // node controls
<< SMESHOp::OpFreeEdge << SMESHOp::OpFreeBorder
<< SMESHOp::OpLength << SMESHOp::OpConnection << SMESHOp::OpEqualEdge // edge controls
+ << SMESHOp::OpDeflection2D
<< SMESHOp::OpFreeFace << SMESHOp::OpLength2D << SMESHOp::OpConnection2D
<< SMESHOp::OpArea << SMESHOp::OpTaper << SMESHOp::OpAspectRatio
<< SMESHOp::OpMinimumAngle << SMESHOp::OpWarpingAngle << SMESHOp::OpSkew
createMenu( SMESHOp::OpSkew, faceId, -1 );
createMenu( SMESHOp::OpMaxElementLength2D, faceId, -1 );
createMenu( SMESHOp::OpEqualFace, faceId, -1 );
+ createMenu( SMESHOp::OpDeflection2D, faceId, -1 );
createMenu( SMESHOp::OpAspectRatio3D, volumeId, -1 );
createMenu( SMESHOp::OpVolume, volumeId, -1 );
createMenu( SMESHOp::OpMaxElementLength3D, volumeId, -1 );
createTool( SMESHOp::OpSkew, ctrl2dTb );
createTool( SMESHOp::OpMaxElementLength2D, ctrl2dTb );
createTool( SMESHOp::OpEqualFace, ctrl2dTb );
+ createTool( SMESHOp::OpDeflection2D, ctrl2dTb );
createTool( SMESHOp::OpAspectRatio3D, ctrl3dTb );
createTool( SMESHOp::OpVolume, ctrl3dTb );
popupMgr()->insert ( action( SMESHOp::OpOverConstrainedFace ), aSubId, -1 );
popupMgr()->setRule( action( SMESHOp::OpOverConstrainedFace ), aMeshInVtkHasFaces, QtxPopupMgr::VisibleRule );
popupMgr()->setRule( action( SMESHOp::OpOverConstrainedFace ), "controlMode = 'eOverConstrainedFace'", QtxPopupMgr::ToggleRule );
+
popupMgr()->insert ( action( SMESHOp::OpEqualFace ), aSubId, -1 );
popupMgr()->setRule( action( SMESHOp::OpEqualFace ), aMeshInVtkHasFaces, QtxPopupMgr::VisibleRule );
popupMgr()->setRule( action( SMESHOp::OpEqualFace ), "controlMode = 'eCoincidentElems2D'", QtxPopupMgr::ToggleRule );
+ popupMgr()->insert ( action( SMESHOp::OpDeflection2D ), aSubId, -1 );
+ popupMgr()->setRule( action( SMESHOp::OpDeflection2D ), aMeshInVtkHasFaces + " && hasGeomReference", QtxPopupMgr::VisibleRule );
+ popupMgr()->setRule( action( SMESHOp::OpDeflection2D ), "controlMode = 'eDeflection2D'", QtxPopupMgr::ToggleRule );
+
aSubId = popupMgr()->insert( tr( "MEN_VOLUME_CTRL" ), anId, -1 ); // VOLUME CONTROLS
popupMgr()->insert ( action( SMESHOp::OpAspectRatio3D ), aSubId, -1 );
aCriterion == SMESH::FT_MaxElementLength3D ||
aCriterion == SMESH::FT_Length ||
aCriterion == SMESH::FT_Length2D ||
+ aCriterion == SMESH::FT_Deflection2D ||
aCriterion == SMESH::FT_BallDiameter );
bool toEnable = (( isDbl && ((ComboItem*)aTable->item(aRow, 1))->value() == SMESH::FT_EqualTo) ||
retval = "len_tol_precision"; break;
case SMESH::FT_Length:
case SMESH::FT_Length2D:
+ case SMESH::FT_Deflection2D:
case SMESH::FT_MaxElementLength2D:
case SMESH::FT_MaxElementLength3D:
case SMESH::FT_BallDiameter:
}
// find out a type of item required by a new criterion and other table features
- int aCriterionType = GetCriterionType(row);
+ int aCriterionType = GetCriterionType(row);
bool anIsDoubleCriterion = false;
bool anIsIntCriterion = false;
bool anIsComboCriterion = false;
// other features:
QList<int> comboIDs; // values to show in a combo item
- int nbCompareSigns = 0; // possible values are 0,1,3
+ int nbCompareSigns = 0; // possible values are 0,1,3
bool isThresholdEditable = false; // actual for "simple" item types
switch ( aCriterionType )
{
case SMESH::FT_Area:
case SMESH::FT_Volume3D:
case SMESH::FT_MaxElementLength2D:
- case SMESH::FT_MaxElementLength3D:
- anIsDoubleCriterion = true; break;
+ case SMESH::FT_MaxElementLength3D: anIsDoubleCriterion = true; break;
case SMESH::FT_FreeBorders:
case SMESH::FT_FreeEdges:
case SMESH::FT_MultiConnection2D: anIsIntCriterion = true; nbCompareSigns = 3; break;
case SMESH::FT_Length:
- case SMESH::FT_Length2D: anIsDoubleCriterion = true; break;
+ case SMESH::FT_Length2D:
+ case SMESH::FT_Deflection2D: anIsDoubleCriterion = true; break;
case SMESH::FT_BelongToMeshGroup: break;
aCriteria[ SMESH::FT_BelongToGenSurface ] = tr("BELONG_TO_GENSURFACE");
aCriteria[ SMESH::FT_LyingOnGeom ] = tr("LYING_ON_GEOM");
aCriteria[ SMESH::FT_Length2D ] = tr("LENGTH2D");
+ aCriteria[ SMESH::FT_Deflection2D ] = tr("DEFLECTION2D");
aCriteria[ SMESH::FT_MultiConnection2D ] = tr("MULTI2D_BORDERS");
aCriteria[ SMESH::FT_FreeFaces ] = tr("FREE_FACES");
aCriteria[ SMESH::FT_BareBorderFace ] = tr("BARE_BORDER_FACE");
\brief Set mesh data source (actor)
\param actor mesh object actor
*/
-void SMESHGUI_ElemInfo::setSource( SMESH_Actor* actor )
+void SMESHGUI_ElemInfo::setSource( SMESH_Actor* actor, SMESH::SMESH_IDSource_var obj )
{
if ( myActor != actor ) {
myActor = actor;
myIsElement = -1;
+ SMESH::SMESH_Mesh_var mesh = obj->GetMesh();
+ myMeshHasShape = ( !mesh->_is_nil() && mesh->HasShapeToMesh() );
clear();
}
}
afunctor.reset( new SMESH::Controls::AspectRatio() );
afunctor->SetMesh( actor()->GetObject()->GetMesh() );
myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "ASPECTRATIO_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) );
- //Minimum angle
+ //Minimum angle
afunctor.reset( new SMESH::Controls::MinimumAngle() );
afunctor->SetMesh( actor()->GetObject()->GetMesh() );
afunctor->SetPrecision( cprecision );
myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "MINIMUMANGLE_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) );
- //Wraping angle
+ //Wraping angle
afunctor.reset( new SMESH::Controls::Warping() );
afunctor->SetMesh( actor()->GetObject()->GetMesh() );
afunctor->SetPrecision( cprecision );
myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "WARP_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) );
- //Skew
+ //Skew
afunctor.reset( new SMESH::Controls::Skew() );
afunctor->SetMesh( actor()->GetObject()->GetMesh() );
afunctor->SetPrecision( cprecision );
myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "SKEW_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) );
- //ElemDiam2D
+ //ElemDiam2D
afunctor.reset( new SMESH::Controls::MaxElementLength2D() );
afunctor->SetMesh( actor()->GetObject()->GetMesh() );
myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "MAX_ELEMENT_LENGTH_2D" ) ).arg( afunctor->GetValue( id ) ) );
+ //min edge length
+ afunctor.reset( new SMESH::Controls::Length2D() );
+ afunctor->SetMesh( actor()->GetObject()->GetMesh() );
+ myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "MIN_ELEM_EDGE" )).arg( afunctor->GetValue( id )) );
}
if( e->GetType() == SMDSAbs_Volume ) {
//AspectRatio3D
afunctor->SetPrecision( cprecision );
QTreeWidgetItem* warpItem = createItem( cntrItem, Bold );
warpItem->setText( 0, tr( "WARP_ELEMENTS" ));
- warpItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );
- //Skew
+ warpItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );
+ //Skew
afunctor.reset( new SMESH::Controls::Skew() );
afunctor->SetMesh( actor()->GetObject()->GetMesh() );
afunctor->SetPrecision( cprecision );
QTreeWidgetItem* skewItem = createItem( cntrItem, Bold );
skewItem->setText( 0, tr( "SKEW_ELEMENTS" ) );
- skewItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );
- //ElemDiam2D
+ skewItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );
+ //Deflection
+ if ( hasShapeToMesh() )
+ {
+ afunctor.reset( new SMESH::Controls::Deflection2D() );
+ afunctor->SetMesh( actor()->GetObject()->GetMesh() );
+ QTreeWidgetItem* deflItem = createItem( cntrItem, Bold );
+ deflItem->setText( 0, tr( "DEFLECTION_2D" ));
+ deflItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id )) );
+ }
+ //ElemDiam2D
afunctor.reset( new SMESH::Controls::MaxElementLength2D() );
afunctor->SetMesh( actor()->GetObject()->GetMesh() );
QTreeWidgetItem* diamItem = createItem( cntrItem, Bold );
diamItem->setText( 0, tr( "MAX_ELEMENT_LENGTH_2D" ));
- diamItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );
+ diamItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );
}
if( e->GetType() == SMDSAbs_Volume ) {
//AspectRatio3D
afunctor->SetMesh( actor()->GetObject()->GetMesh() );
QTreeWidgetItem* ratlItem3 = createItem( cntrItem, Bold );
ratlItem3->setText( 0, tr( "ASPECTRATIO_3D_ELEMENTS" ) );
- ratlItem3->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );
+ ratlItem3->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );
//Volume
afunctor.reset( new SMESH::Controls::Volume() );
afunctor->SetMesh( actor()->GetObject()->GetMesh() );
diam3Item->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );
}
+ //min edge length
+ afunctor.reset( new SMESH::Controls::Length2D() );
+ afunctor->SetMesh( actor()->GetObject()->GetMesh() );
+ QTreeWidgetItem* minEdgeItem = createItem( cntrItem, Bold );
+ minEdgeItem->setText( 0, tr( "MIN_ELEM_EDGE" ));
+ minEdgeItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id )) );
+
// gravity center
XYZ gc = gravityCenter( e );
QTreeWidgetItem* gcItem = createItem( elemItem, Bold );
SMESH::GetNameOfSelectedElements( selector, IO, ID ) :
SMESH::GetNameOfSelectedNodes( selector, IO, ID );
}
- myElemInfo->setSource( myActor ) ;
+ myElemInfo->setSource( myActor, obj ) ;
if ( nb > 0 ) {
myID->setText( ID.trimmed() );
QSet<long> ids;
SMESHGUI_ElemInfo( QWidget* = 0 );
~SMESHGUI_ElemInfo();
- void setSource( SMESH_Actor* );
+ void setSource( SMESH_Actor*, SMESH::SMESH_IDSource_var );
void showInfo( long, bool );
void showInfo( QSet<long>, bool );
void clear();
QWidget* frame() const;
SMESH_Actor* actor() const;
bool isElements() const;
+ bool hasShapeToMesh() const { return myMeshHasShape; }
virtual void information( const QList<long>& ) = 0;
virtual void clearInternal();
QWidget* myFrame;
ExtraWidget* myExtra;
int myIndex;
+ bool myMeshHasShape;
};
class SMESHGUI_EXPORT SMESHGUI_SimpleElemInfo : public SMESHGUI_ElemInfo
/*!
* \brief Selects a recently created mesh or sub-mesh if necessary
*
- * Virtual method redefined from base class called when operation is commited
+ * Virtual method redefined from base class called when operation is committed
* selects a recently created mesh or sub-mesh if necessary. Allows to perform
* selection when the custom selection filters are removed.
*/
}
}
else { // no geometry defined
- myDlg->enableTab( SMESH::DIM_3D );
- QStringList hypList;
- availableHyps( SMESH::DIM_3D, Algo, hypList,
- myAvailableHypData[SMESH::DIM_3D][Algo]);
- SMESHGUI_MeshTab* aTab = myDlg->tab( SMESH::DIM_3D );
- aTab->setAvailableHyps( Algo, hypList );
- for (int i = SMESH::DIM_0D;i < SMESH::DIM_3D; ++i) {
- myDlg->disableTab(i);
+ QStringList hypList;
+ for ( int dim = SMESH::DIM_0D; dim <= SMESH::DIM_3D; dim++ )
+ {
+ availableHyps( dim, Algo, hypList, myAvailableHypData[dim][Algo]);
+ myDlg->tab( dim )->setAvailableHyps( Algo, hypList );
+ if ( hypList.empty() ) myDlg->disableTab( dim );
+ else myDlg->enableTab( dim );
}
myMaxShapeDim = -1;
//Hide labels and fields (Mesh and Geometry)
//================================================================================
/*!
- * \Brief Returns tab dimention
+ * \Brief Returns tab dimension
* \param tab - the tab in the dlg
* \param dlg - my dialogue
- * \retval int - dimention
+ * \retval int - dimension
*/
//================================================================================
static int getTabDim (const QObject* tab, SMESHGUI_MeshDlg* dlg )
if ( myIgnoreAlgoSelection )
return;
- int aDim = theDim < 0 ? getTabDim( sender(), myDlg ): theDim;
+ int curDim = getTabDim( sender(), myDlg );
+ int aDim = theDim < 0 ? curDim : theDim;
if (aDim == -1)
return;
myDlg->tab( dim )->setAvailableHyps( Algo, anAvailable );
noCompatible = anAvailable.isEmpty();
algoIndex = myAvailableHypData[dim][Algo].indexOf( curAlgo );
- if ( !isSubmesh && algoIndex < 0 && soleCompatible && !forward && dim != SMESH::DIM_0D) {
+ if ( !isSubmesh && algoIndex < 0 && soleCompatible && !forward && dim == curDim ) {
// select the sole compatible algo
algoIndex = 0;
}
hypIndex = this->find( curHyp, myExistingHyps[ dim ][ type ]);
else
hypIndex = -1;
- if ( !isSubmesh && myToCreate && hypIndex < 0 && anExisting.count() == 1 ) {
+ if ( !isSubmesh && myToCreate && hypIndex < 0 && anExisting.count() == 1 && dim == curDim )
+ {
// none is yet selected => select the sole existing if it is not optional
CORBA::String_var hypTypeName = myExistingHyps[ dim ][ type ].first().first->GetName();
bool isOptional = true;
{
// Call hypothesis creation server method (without GUI)
SMESH::SMESH_Hypothesis_var aHyp =
- SMESH::CreateHypothesis(aHypName, aHypName, true);
+ SMESH::CreateHypothesis(aHypName, aHypData->Label, true);
aHyp.out();
}
else
aCreator->create( true, aHypName, myDlg, 0, QString::null );
else {
SMESH::SMESH_Hypothesis_var aHyp =
- SMESH::CreateHypothesis(aHypName, aHypName, true);
+ SMESH::CreateHypothesis(aHypName, aHypData->Label, true);
aHyp.out();
}
delete aCreator;
// Get hypotheses and algorithms assigned to the mesh/sub-mesh
QStringList anExisting;
- const int lastDim = ( myIsOnGeometry ) ? SMESH::DIM_0D : SMESH::DIM_3D;
+ const int lastDim = ( myIsOnGeometry ) ? SMESH::DIM_0D : SMESH::DIM_2D;
bool algoFound = false;
for ( int dim = SMESH::DIM_3D; dim >= lastDim; --dim )
{
/*!
* \brief Edits mesh or sub-mesh
* \param theMess - Output parameter intended for returning error message
- * \retval bool - TRUE if mesh is edited succesfully, FALSE otherwise
+ * \retval bool - TRUE if mesh is edited successfully, FALSE otherwise
*
* Assigns new name hypotheses and algoriths to the mesh or sub-mesh
*/
// Set new name
QString aName = myDlg->objectText( SMESHGUI_MeshDlg::Obj );
SMESH::SetName( pObj, aName );
- int aDim = ( myIsOnGeometry ) ? SMESH::DIM_0D : SMESH::DIM_3D;
+ int aDim = ( myIsOnGeometry ) ? SMESH::DIM_0D : SMESH::DIM_2D;
// First, remove old algos in order to avoid messages on algorithm hiding
for ( int dim = aDim; dim <= SMESH::DIM_3D; dim++ )
*
* method redefined from base class verifies whether given operator is valid for
* this one (i.e. can be started "above" this operator). In current implementation method
- * retuns false if theOtherOp operation is not intended for deleting objects or mesh
+ * returns false if theOtherOp operation is not intended for deleting objects or mesh
* elements.
*/
//================================================================================
}
if ( !myIsOnGeometry )
for ( int i = SMESH::DIM_0D; i <= SMESH::DIM_3D; i++ ) {
- if ( i < SMESH::DIM_3D ) myDlg->disableTab( i );
- else myDlg->enableTab( i );
+ bool disable = myAvailableHypData[i][Algo].isEmpty();
+ if ( disable ) myDlg->disableTab( i );
+ else myDlg->enableTab( i );
}
else
for ( int i = SMESH::DIM_0D; i <= SMESH::DIM_3D; i++ ) {
OpSkew = 3210, // MENU CONTROLS - SKEW
OpMaxElementLength2D = 3211, // MENU CONTROLS - ELEMENT DIAMETER 2D
OpEqualFace = 3212, // MENU CONTROLS - DOUBLE FACES
+ OpDeflection2D = 3213, // MENU CONTROLS - DEFLECTION 2D
OpAspectRatio3D = 3300, // MENU CONTROLS - ASPECT RATIO 3D
OpVolume = 3301, // MENU CONTROLS - VOLUME
OpMaxElementLength3D = 3302, // MENU CONTROLS - ELEMENT DIAMETER 3D
switch( actor->GetControlMode() ) {
case SMESH_Actor::eLength: mode = "eLength"; break;
case SMESH_Actor::eLength2D: mode = "eLength2D"; break;
+ case SMESH_Actor::eDeflection2D: mode = "eDeflection2D"; break;
case SMESH_Actor::eFreeEdges: mode = "eFreeEdges"; break;
case SMESH_Actor::eFreeNodes: mode = "eFreeNodes"; break;
case SMESH_Actor::eFreeBorders: mode = "eFreeBorders"; break;
return "eNone";
}
+//=======================================================================
+//function : isNumFunctor
+//purpose : return true if a given actor is shown using a numeric functor
+//=======================================================================
+
bool SMESHGUI_Selection::isNumFunctor( int ind ) const
{
bool result = false;
switch( actor->GetControlMode() ) {
case SMESH_Actor::eLength:
case SMESH_Actor::eLength2D:
+ case SMESH_Actor::eDeflection2D:
case SMESH_Actor::eMultiConnection:
case SMESH_Actor::eMultiConnection2D:
case SMESH_Actor::eArea:
//=======================================================================
//function : facesOrientationMode
-//purpose :
+//purpose :
//=======================================================================
QString SMESHGUI_Selection::facesOrientationMode( int ind ) const
<source>ICON_LENGTH_2D</source>
<translation>mesh_length_2d.png</translation>
</message>
+ <message>
+ <source>ICON_DEFLECTION_2D</source>
+ <translation>mesh_deflection.png</translation>
+ </message>
<message>
<source>ICON_MAP</source>
<translation>mesh_pattern.png</translation>
<source>MIN_DIAG_ELEMENTS</source>
<translation>Minimum diagonal</translation>
</message>
+ <message>
+ <source>MIN_ELEM_EDGE</source>
+ <translation>Minimum Edge Length</translation>
+ </message>
<message>
<source>ASPECTRATIO_3D_ELEMENTS</source>
<translation>Aspect Ratio 3D</translation>
<source>LENGTH2D_EDGES</source>
<translation>Length 2D</translation>
</message>
+ <message>
+ <source>DEFLECTION2D_FACES</source>
+ <translation>Deflection 2D</translation>
+ </message>
<message>
<source>LENGTH_EDGES</source>
<translation>Length</translation>
<source>MAX_ELEMENT_LENGTH_3D</source>
<translation>Element Diameter 3D</translation>
</message>
+ <message>
+ <source>DEFLECTION_2D</source>
+ <translation>Deflection 2D</translation>
+ </message>
<message>
<source>MEN_ADD</source>
<translation>Add</translation>
<source>MEN_LENGTH_2D</source>
<translation>Length 2D</translation>
</message>
+ <message>
+ <source>MEN_DEFLECTION_2D</source>
+ <translation>Deflection 2D</translation>
+ </message>
<message>
<source>MEN_MAP</source>
<translation>Pattern Mapping</translation>
<source>STB_LENGTH_2D</source>
<translation>Length 2D</translation>
</message>
+ <message>
+ <source>STB_DEFLECTION_2D</source>
+ <translation>Deflection 2D</translation>
+ </message>
<message>
<source>STB_MAP</source>
<translation>Pattern mapping</translation>
<source>TOP_LENGTH_2D</source>
<translation>Length 2D</translation>
</message>
+ <message>
+ <source>TOP_DEFLECTION_2D</source>
+ <translation>Deflection 2D</translation>
+ </message>
<message>
<source>TOP_MAP</source>
<translation>Pattern mapping</translation>
<source>LENGTH2D</source>
<translation>Length 2D</translation>
</message>
+ <message>
+ <source>DEFLECTION2D</source>
+ <translation>Deflection 2D</translation>
+ </message>
<message>
<source>LESS_THAN</source>
<translation>Less than</translation>
${CAS_TKMesh}
${Boost_LIBRARIES}
SMDS
-)
+ )
# --- headers ---
SMESH_MAT2d.cxx
SMESH_FreeBorders.cxx
SMESH_ControlPnt.cxx
+ SMESH_FillHole.cxx
)
# --- rules ---
--- /dev/null
+// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE
+//
+// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+//
+// 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 : SMESH_FillHole.cxx
+// Created : Tue Sep 26 15:11:17 2017
+// Author : Edward AGAPOV (eap)
+//
+
+#include "SMESH_MeshAlgos.hxx"
+
+#include "SMESH_Comment.hxx"
+
+#include "SMESH_TypeDefs.hxx"
+#include "SMDS_Mesh.hxx"
+
+#include <Utils_SALOME_Exception.hxx>
+
+#include <boost/intrusive/circular_list_algorithms.hpp>
+#include <boost/container/flat_map.hpp>
+
+#include <Bnd_B3d.hxx>
+
+namespace
+{
+ bool isSmallAngle( double cos2 )
+ {
+ // cosine of min angle at which adjacent faces are considered overlapping
+ const double theMinCos2 = 0.996 * 0.996; // ~5 degrees
+ return ( cos2 > theMinCos2 );
+ }
+
+ struct BEdge;
+ typedef std::multimap< double, BEdge* > TAngleMap;
+ typedef std::map< const SMDS_MeshElement*, int > TFaceIndMap;
+
+ //--------------------------------------------------------------------------------
+ /*!
+ * \brief Edge of a free border
+ */
+ struct BEdge
+ {
+ const SMDS_MeshNode* myNode1;
+ const SMDS_MeshNode* myNode2;
+ const SMDS_MeshElement* myFace; // face adjacent to the border
+
+ gp_XYZ myFaceNorm;
+ gp_XYZ myDir; // myNode1 -> myNode2
+ double myDirCoef; // 1. or -1, to make myDir oriented as myNodes in myFace
+ double myLength; // between nodes
+ double myAngleWithPrev; // between myDir and -myPrev->myDir
+ double myMinMaxRatio; // of a possible triangle sides
+ TAngleMap::iterator myAngleMapPos;
+ double myOverlapAngle; // angle delta due to overlapping
+ const SMDS_MeshNode* myNode1Shift; // nodes created to avoid overlapping of faces
+ const SMDS_MeshNode* myNode2Shift;
+
+ BEdge* myPrev; // neighbors in the border
+ BEdge* myNext;
+
+ BEdge(): myNode1Shift(0), myNode2Shift(0) {}
+ void Init( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2,
+ const SMDS_MeshElement* f=0,
+ const SMDS_MeshNode* nf1=0, const SMDS_MeshNode* nf2=0 );
+ void ComputeAngle( bool reverseAngle = false );
+ void ShiftOverlapped( const SMDS_MeshNode* oppNode,
+ const TFaceIndMap& capFaceWithBordInd,
+ SMDS_Mesh& mesh,
+ std::vector<const SMDS_MeshElement*>& newFaces);
+ void MakeShiftfFaces( SMDS_Mesh& mesh,
+ std::vector<const SMDS_MeshElement*>& newFaces,
+ const bool isReverse );
+ gp_XYZ GetInFaceDir() const { return myFaceNorm ^ myDir * myDirCoef; }
+ double ShapeFactor() const { return 0.5 * ( 1. - myMinMaxRatio ); }
+ void InsertSelf(TAngleMap& edgesByAngle, bool isReverseFaces, bool reBind, bool useOverlap )
+ {
+ if ( reBind ) edgesByAngle.erase( myAngleMapPos );
+ double key = (( isReverseFaces ? 2 * M_PI - myAngleWithPrev : myAngleWithPrev )
+ + myOverlapAngle * useOverlap
+ + ShapeFactor() );
+ myAngleMapPos = edgesByAngle.insert( std::make_pair( key, this ));
+ }
+
+ // traits used by boost::intrusive::circular_list_algorithms
+ typedef BEdge node;
+ typedef BEdge * node_ptr;
+ typedef const BEdge * const_node_ptr;
+ static node_ptr get_next(const_node_ptr n) { return n->myNext; }
+ static void set_next(node_ptr n, node_ptr next) { n->myNext = next; }
+ static node_ptr get_previous(const_node_ptr n) { return n->myPrev; }
+ static void set_previous(node_ptr n, node_ptr prev){ n->myPrev = prev; }
+ };
+
+ //================================================================================
+ /*!
+ * \brief Initialize a border edge data
+ */
+ //================================================================================
+
+ void BEdge::Init( const SMDS_MeshNode* n1,
+ const SMDS_MeshNode* n2,
+ const SMDS_MeshElement* newFace, // new cap face
+ const SMDS_MeshNode* nf1,
+ const SMDS_MeshNode* nf2 )
+ {
+ myNode1 = n1;
+ myNode2 = n2;
+ myDir = SMESH_NodeXYZ( n2 ) - SMESH_NodeXYZ( n1 );
+ myLength = myDir.Modulus();
+ if ( myLength > std::numeric_limits<double>::min() )
+ myDir /= myLength;
+
+ myFace = newFace;
+ if ( !myFace )
+ {
+ TIDSortedElemSet elemSet, avoidSet;
+ int ind1, ind2;
+ myFace = SMESH_MeshAlgos::FindFaceInSet( n1, n2, elemSet, avoidSet, &ind1, &ind2 );
+ if ( !myFace )
+ throw SALOME_Exception( SMESH_Comment("No face sharing nodes #")
+ << myNode1->GetID() << " and #" << myNode2->GetID());
+ avoidSet.insert( myFace );
+ if ( SMESH_MeshAlgos::FindFaceInSet( n1, n2, elemSet, avoidSet ))
+ throw SALOME_Exception( SMESH_Comment("No free border between nodes #")
+ << myNode1->GetID() << " and #" << myNode2->GetID());
+
+ myDirCoef = SMESH_MeshAlgos::IsRightOrder( myFace, myNode1, myNode2 ) ? 1. : -1.;
+ }
+
+ if (! SMESH_MeshAlgos::FaceNormal( myFace, myFaceNorm, /*normalized=*/false ))
+ {
+ SMDS_ElemIteratorPtr fIt = myNode1->GetInverseElementIterator( SMDSAbs_Face );
+ while ( fIt->more() )
+ if ( SMESH_MeshAlgos::FaceNormal( fIt->next(), myFaceNorm, /*normalized=*/false ))
+ break;
+ }
+
+ if ( newFace )
+ {
+ myFace = 0;
+ myDirCoef = SMESH_MeshAlgos::IsRightOrder( newFace, nf1, nf2 ) ? 1. : -1.;
+ if ( myPrev->myNode2 == n1 )
+ myNode1Shift = myPrev->myNode2Shift;
+ if ( myNext->myNode1 == n2 )
+ myNode2Shift = myNext->myNode1Shift;
+ }
+ else if ( myDirCoef * myPrev->myDirCoef < 0 ) // different orientation of faces
+ {
+ myFaceNorm *= -1;
+ myDirCoef *= -1;
+ }
+ }
+
+ //================================================================================
+ /*!
+ * \brief Compute myAngleWithPrev
+ */
+ //================================================================================
+
+ void BEdge::ComputeAngle( bool theReverseAngle )
+ {
+ myAngleWithPrev = acos( myDir.Dot( myPrev->myDir.Reversed() ));
+
+ bool isObtuse;
+ gp_XYZ inFaceDirNew = myDir - myPrev->myDir;
+ gp_XYZ inFaceDir1 = myPrev->GetInFaceDir();
+ gp_XYZ inFaceDir2 = this->GetInFaceDir();
+ double dot1 = inFaceDirNew * inFaceDir1;
+ double dot2 = inFaceDirNew * inFaceDir2;
+ bool isOverlap1 = ( dot1 > 0 );
+ bool isOverlap2 = ( dot2 > 0 );
+ if ( !myPrev->myFace )
+ isObtuse = isOverlap1;
+ else if ( !myFace )
+ isObtuse = isOverlap2;
+ else
+ {
+ double dt1 = myDir.Dot( myPrev->myFaceNorm );
+ double dt2 = myPrev->myDir.Dot( myFaceNorm );
+ isObtuse = ( dt1 > 0 || dt2 < 0 ); // suppose face normals point outside the border
+ if ( theReverseAngle )
+ isObtuse = !isObtuse;
+ }
+ if ( isObtuse )
+ {
+ myAngleWithPrev = 2 * M_PI - myAngleWithPrev;
+ }
+
+ // if ( ! isObtuse )
+ // isObtuse =
+ // isSmallAngle( 1 - myDir.CrossSquareMagnitude( myPrev->myDir )); // edges co-directed
+
+ myOverlapAngle = 0;
+ //if ( !isObtuse )
+ {
+ // check if myFace and a triangle built on this and prev edges overlap
+ if ( isOverlap1 )
+ {
+ double cos2 = dot1 * dot1 / inFaceDirNew.SquareModulus() / inFaceDir1.SquareModulus();
+ myOverlapAngle += 1. * M_PI * cos2;
+ }
+ if ( isOverlap2 )
+ {
+ double cos2 = dot2 * dot2 / inFaceDirNew.SquareModulus() / inFaceDir2.SquareModulus();
+ myOverlapAngle += 1. * M_PI * cos2;
+ }
+ }
+
+ {
+ double len3 = SMESH_NodeXYZ( myPrev->myNode1 ).Distance( myNode2 );
+ double minLen = Min( myLength, Min( myPrev->myLength, len3 ));
+ double maxLen = Max( myLength, Max( myPrev->myLength, len3 ));
+ myMinMaxRatio = minLen / maxLen;
+ }
+ }
+
+ //================================================================================
+ /*!
+ * \brief Check if myFace is overlapped by a triangle formed by myNode's and a
+ * given node. If so, create shifted nodes to avoid overlapping
+ */
+ //================================================================================
+
+ void BEdge::ShiftOverlapped( const SMDS_MeshNode* theOppNode,
+ const TFaceIndMap& theCapFaceWithBordInd,
+ SMDS_Mesh& theMesh,
+ std::vector<const SMDS_MeshElement*>& theNewFaces )
+ {
+ if ( myNode1Shift && myNode2Shift )
+ return;
+
+ gp_XYZ inNewFaceDir = SMESH_NodeXYZ( theOppNode ) - SMESH_NodeXYZ( myNode1 );
+ double dot = inNewFaceDir.Dot( myFaceNorm );
+ double cos2 = dot * dot / myFaceNorm.SquareModulus() / inNewFaceDir.SquareModulus();
+ bool isOverlap = ( isSmallAngle( 1 - cos2 ) && GetInFaceDir() * inNewFaceDir > 0 );
+
+ if ( isOverlap )
+ {
+ gp_XYZ shift = myFaceNorm / myLength / 4;
+ if ( myFace )
+ shift.Reverse();
+ if ( !myNode1Shift )
+ {
+ gp_XYZ p = SMESH_NodeXYZ( myNode1 ) + shift;
+ myNode1Shift = theMesh.AddNode( p.X(), p.Y(), p.Z() );
+ myPrev->myNode2Shift = myNode1Shift;
+ }
+ if ( !myNode2Shift )
+ {
+ gp_XYZ p = SMESH_NodeXYZ( myNode2 ) + shift;
+ myNode2Shift = theMesh.AddNode( p.X(), p.Y(), p.Z() );
+ myNext->myNode1Shift = myNode2Shift;
+ }
+
+ // MakeShiftfFaces() for already created cap faces
+ for ( int is2nd = 0; is2nd < 2; ++is2nd )
+ {
+ const SMDS_MeshNode* ns = is2nd ? myNode2Shift : myNode1Shift;
+ const SMDS_MeshNode* n = is2nd ? myNode2 : myNode1;
+ if ( !ns ) continue;
+
+ SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator( SMDSAbs_Face );
+ while ( fIt->more() )
+ {
+ const SMDS_MeshElement* f = fIt->next();
+ if ( !f->isMarked() ) continue;
+
+ TFaceIndMap::const_iterator f2i = theCapFaceWithBordInd.find( f );
+ if ( f2i == theCapFaceWithBordInd.end() )
+ continue;
+ const SMDS_MeshNode* nf1 = f->GetNode( f2i->second );
+ const SMDS_MeshNode* nf2 = f->GetNode(( f2i->second+1 ) % f->NbNodes() );
+ if ( nf1 == n || nf2 == n )
+ {
+ BEdge tmpE;
+ tmpE.myPrev = tmpE.myNext = this;
+ tmpE.Init( nf1, nf2, f, nf1, nf2 );
+ if ( !tmpE.myNode1Shift && !tmpE.myNode2Shift )
+ tmpE.Init( nf2, nf1, f, nf2, nf1 );
+ tmpE.myFace = f;
+ tmpE.MakeShiftfFaces( theMesh, theNewFaces, tmpE.myDirCoef < 0 );
+ }
+ std::vector< const SMDS_MeshNode* > nodes( f->begin_nodes(), f->end_nodes() );
+ nodes[ f->GetNodeIndex( n ) ] = ns;
+ theMesh.ChangeElementNodes( f, &nodes[0], nodes.size() );
+ }
+ }
+ }
+ }
+
+ //================================================================================
+ /*!
+ * \brief Create a triangle
+ */
+ //================================================================================
+
+ const SMDS_MeshElement* MakeTria( SMDS_Mesh& mesh,
+ const SMDS_MeshNode* n1,
+ const SMDS_MeshNode* n2,
+ const SMDS_MeshNode* n3,
+ const bool isReverse )
+ {
+ if ( isReverse )
+ return mesh.AddFace( n1, n3, n2 );
+ return mesh.AddFace( n1, n2, n3 );
+ }
+
+ //================================================================================
+ /*!
+ * \brief Create a quadrangle
+ */
+ //================================================================================
+
+ // const SMDS_MeshElement* MakeQuad( SMDS_Mesh& mesh,
+ // const SMDS_MeshNode* n1,
+ // const SMDS_MeshNode* n2,
+ // const SMDS_MeshNode* n3,
+ // const SMDS_MeshNode* n4,
+ // const bool isReverse )
+ // {
+ // if ( isReverse )
+ // return mesh.AddFace( n4, n3, n2, n1 );
+ // return mesh.AddFace( n1, n2, n3, n4 );
+ // }
+
+ //================================================================================
+ /*!
+ * \brief Create faces on myNode* and myNode*Shift
+ */
+ //================================================================================
+
+ void BEdge::MakeShiftfFaces(SMDS_Mesh& mesh,
+ std::vector<const SMDS_MeshElement*>& newFaces,
+ const bool isReverse )
+ {
+ if ( !myFace )
+ return;
+ if ( myNode1Shift && myNode2Shift )
+ {
+ newFaces.push_back( MakeTria( mesh, myNode1, myNode2, myNode2Shift, isReverse ));
+ newFaces.push_back( MakeTria( mesh, myNode1, myNode2Shift, myNode1Shift, isReverse ));
+ }
+ else if ( myNode1Shift )
+ {
+ newFaces.push_back( MakeTria( mesh, myNode1, myNode2, myNode1Shift, isReverse ));
+ }
+ else if ( myNode2Shift )
+ {
+ newFaces.push_back( MakeTria( mesh, myNode1, myNode2, myNode2Shift, isReverse ));
+ }
+ }
+
+} // namespace
+
+//================================================================================
+/*!
+ * \brief Fill with 2D elements a hole defined by a TFreeBorder
+ */
+//================================================================================
+
+void SMESH_MeshAlgos::FillHole(const SMESH_MeshAlgos::TFreeBorder & theFreeBorder,
+ SMDS_Mesh& theMesh,
+ std::vector<const SMDS_MeshElement*>& theNewFaces)
+{
+ if ( theFreeBorder.size() < 4 || // at least 3 nodes
+ theFreeBorder[0] != theFreeBorder.back() ) // the hole must be closed
+ return;
+
+ // prepare data of the border
+
+ ObjectPool< BEdge > edgeAllocator(1024);
+ boost::intrusive::circular_list_algorithms< BEdge > circularList;
+ BEdge* edge;
+ BEdge* edge0 = edgeAllocator.getNew();
+ BEdge* edgePrev = edge0;
+ circularList.init_header( edge0 );
+ edge0->Init( theFreeBorder[0], theFreeBorder[1], 0 );
+ Bnd_B3d box;
+ box.Add( SMESH_NodeXYZ( edge0->myNode1 ));
+ for ( size_t i = 2; i < theFreeBorder.size(); ++i )
+ {
+ edge = edgeAllocator.getNew();
+ circularList.link_after( edgePrev, edge );
+ edge->Init( theFreeBorder[i-1], theFreeBorder[i] );
+ edge->ComputeAngle();
+ edgePrev = edge;
+ box.Add( SMESH_NodeXYZ( edge->myNode1 ));
+ }
+ edge0->ComputeAngle();
+
+ // check if face normals point outside the border
+
+ gp_XYZ hSize = 0.5 * ( box.CornerMax() - box.CornerMin() );
+ const double hDelta = 1e-6 * hSize.Modulus();
+ hSize -= gp_XYZ( hDelta, hDelta, hDelta );
+ if ( hSize.X() < 0 ) hSize.SetX(hDelta);
+ if ( hSize.Y() < 0 ) hSize.SetY(hDelta);
+ if ( hSize.Z() < 0 ) hSize.SetZ(hDelta);
+ box.SetHSize( hSize ); // decrease the box by hDelta
+
+ size_t nbEdges = theFreeBorder.size() - 1;
+ edge = edge0;
+ int nbRev = 0, nbFrw = 0;
+ double angTol = M_PI - ( nbEdges - 2 ) * M_PI / nbEdges, sumDirCoeff = 0;
+ for ( size_t i = 0; i < nbEdges; ++i, edge = edge->myNext )
+ {
+ if ( box.IsOut( SMESH_NodeXYZ( edge->myNode1 )) &&
+ edge->myOverlapAngle < 0.1 * M_PI )
+ {
+ nbRev += edge->myAngleWithPrev > M_PI + angTol;
+ nbFrw += edge->myAngleWithPrev < M_PI - angTol;
+ }
+ sumDirCoeff += edge->myDirCoef;
+
+ // unmark all adjacent faces, new faces will be marked
+ SMDS_ElemIteratorPtr fIt = edge->myNode1->GetInverseElementIterator( SMDSAbs_Face );
+ while ( fIt->more() )
+ fIt->next()->setIsMarked( false );
+ }
+ bool isReverseAngle = ( nbRev > nbFrw ); // true == face normals point inside the border
+ //std::cout << "nbRev="<< nbRev << ", nbFrw="<< nbFrw<<std::endl;
+
+ // sort border edges by myAngleWithPrev
+
+ TAngleMap edgesByAngle;
+ bool useOverlap = true; // to add BEdge.myOverlapAngle when filling edgesByAngle
+ edge = edge0;
+ for ( size_t i = 0; i < nbEdges; ++i, edge = edge->myNext )
+ edge->InsertSelf( edgesByAngle, isReverseAngle, /*reBind=*/false, useOverlap );
+
+ // create triangles to fill the hole
+
+ //compare order of nodes in the edges with their order in faces
+ bool isReverse = sumDirCoeff > 0.5 * nbEdges;
+
+ // faces filling the hole (cap faces) and indices of border edges in them
+ TFaceIndMap capFaceWithBordInd;
+
+ theNewFaces.reserve( nbEdges - 2 );
+ std::vector< const SMDS_MeshNode* > nodes(3);
+ while ( edgesByAngle.size() > 2 )
+ {
+ TAngleMap::iterator a2e = edgesByAngle.begin();
+ edge = a2e->second;
+ if ( useOverlap &&
+ a2e->first - edge->ShapeFactor() > M_PI - angTol ) // all new triangles need shift
+ {
+ // re-sort the edges w/o overlap consideration
+ useOverlap = false;
+ nbEdges = edgesByAngle.size();
+ edgesByAngle.clear();
+ for ( size_t i = 0; i < nbEdges; ++i, edge = edge->myNext )
+ edge->InsertSelf( edgesByAngle, isReverseAngle, /*reBind=*/false, useOverlap );
+ a2e = edgesByAngle.begin();
+ }
+ edge = a2e->second;
+ edgePrev = edge->myPrev;
+
+ // create shift nodes and faces
+ edgePrev->ShiftOverlapped( edge->myNode2, capFaceWithBordInd, theMesh, theNewFaces );
+ edge->ShiftOverlapped( edgePrev->myNode1, capFaceWithBordInd, theMesh, theNewFaces );
+ edge ->MakeShiftfFaces( theMesh, theNewFaces, isReverse );
+ edgePrev->MakeShiftfFaces( theMesh, theNewFaces, isReverse );
+
+ // make a cap face
+ //nodes.resize( 3 );
+ nodes[0] = edgePrev->myNode1Shift ? edgePrev->myNode1Shift : edgePrev->myNode1;
+ nodes[1] = edgePrev->myNode2Shift ? edgePrev->myNode2Shift : edgePrev->myNode2;
+ nodes[2] = edge->myNode2Shift ? edge->myNode2Shift : edge->myNode2;
+ theNewFaces.push_back( MakeTria( theMesh, nodes[0], nodes[1], nodes[2], isReverse ));
+ // std::cout << nodes[1]->GetID() << " " << nodes[0]->GetID() << " " << nodes[2]->GetID()
+ // << " " << edge->myAngleWithPrev << std::endl;
+
+ // remember a border edge within the new cap face
+ theNewFaces.back()->setIsMarked( true );
+ if ( edgePrev->myFace )
+ capFaceWithBordInd.insert( std::make_pair( theNewFaces.back(), isReverse ? 2 : 0 ));
+ if ( edge->myFace )
+ capFaceWithBordInd.insert( std::make_pair( theNewFaces.back(), 1 ));
+
+ // remove edgePrev from the list and update <edge>
+ edgesByAngle.erase( edgePrev->myAngleMapPos );
+ circularList.unlink( edgePrev ); // remove edgePrev from the border
+
+ edge->Init( edgePrev->myNode1, edge->myNode2, theNewFaces.back(), nodes[0], nodes[2] );
+ edge->ComputeAngle( isReverseAngle );
+ edge->InsertSelf( edgesByAngle, /*isReverse=*/false, /*reBind=*/true, useOverlap );
+ edge->myNext->ComputeAngle( isReverseAngle );
+ edge->myNext->InsertSelf( edgesByAngle, /*isReverse=*/false, /*reBind=*/true, useOverlap );
+ // std::cout << "A " << edge->myNode1->GetID() << " " << edge->myAngleWithPrev
+ // << " " << edge->myNext->myNode1->GetID() << " " << edge->myNext->myAngleWithPrev
+ // << std::endl;
+ }
+ edge = edgesByAngle.begin()->second;
+ edge-> MakeShiftfFaces( theMesh, theNewFaces, isReverse );
+ edge->myNext->MakeShiftfFaces( theMesh, theNewFaces, isReverse );
+}
if ( myID < 0 )
{
myID = id;
- if ( myNext )
- myNext->SetID( id + 1 );
+
+ for ( BEdge* be = myNext; be && be->myID < 0; be = be->myNext )
+ {
+ be->myID = ++id;
+ }
}
}
//================================================================================
} // SMESH_MeshAlgos::FindCoincidentFreeBorders()
+//================================================================================
+/*
+ * Returns all TFreeBorder's. Optionally check if the mesh is manifold
+ * and if faces are correctly oriented.
+ */
+//================================================================================
+
+void SMESH_MeshAlgos::FindFreeBorders(SMDS_Mesh& theMesh,
+ TFreeBorderVec & theFoundFreeBordes,
+ const bool theClosedOnly,
+ bool* theIsManifold,
+ bool* theIsGoodOri)
+{
+ bool isManifold = true;
+
+ // find free links
+ typedef NCollection_DataMap<SMESH_TLink, const SMDS_MeshElement*, SMESH_TLink > TLink2FaceMap;
+ TLink2FaceMap linkMap;
+ int nbSharedLinks = 0;
+ SMDS_FaceIteratorPtr faceIt = theMesh.facesIterator();
+ while ( faceIt->more() )
+ {
+ const SMDS_MeshElement* face = faceIt->next();
+ if ( !face ) continue;
+
+ const SMDS_MeshNode* n0 = face->GetNode( face->NbNodes() - 1 );
+ SMDS_NodeIteratorPtr nodeIt = face->interlacedNodesIterator();
+ while ( nodeIt->more() )
+ {
+ const SMDS_MeshNode* n1 = nodeIt->next();
+ SMESH_TLink link( n0, n1 );
+ if ( const SMDS_MeshElement** faceInMap = linkMap.ChangeSeek( link ))
+ {
+ if ( *faceInMap )
+ {
+ if ( theIsGoodOri && *theIsGoodOri && !IsRightOrder( *faceInMap, n1, n0 ))
+ *theIsGoodOri = false;
+ }
+ else
+ {
+ isManifold = false;
+ }
+ nbSharedLinks += bool( *faceInMap );
+ *faceInMap = 0;
+ }
+ else
+ {
+ linkMap.Bind( link, face );
+ }
+ n0 = n1;
+ }
+ }
+ if ( theIsManifold )
+ *theIsManifold = isManifold;
+
+ if ( linkMap.Extent() == nbSharedLinks )
+ return;
+
+ // form free borders
+ std::set < BNode > bNodes;
+ std::vector< BEdge > bEdges( linkMap.Extent() - nbSharedLinks );
+
+ TLink2FaceMap::Iterator linkIt( linkMap );
+ for ( int iEdge = 0; linkIt.More(); linkIt.Next() )
+ {
+ if ( !linkIt.Value() ) continue;
+ const SMESH_TLink & link = linkIt.Key();
+ std::set< BNode >::iterator n1 = bNodes.insert( BNode( link.node1() )).first;
+ std::set< BNode >::iterator n2 = bNodes.insert( BNode( link.node2() )).first;
+ bEdges[ iEdge ].Set( &*n1, &*n2, linkIt.Value(), iEdge+1 );
+ n1->AddLinked( & bEdges[ iEdge ] );
+ n2->AddLinked( & bEdges[ iEdge ] );
+ ++iEdge;
+ }
+ linkMap.Clear();
+
+ // assign IDs to borders
+ std::vector< BEdge* > borders; // 1st of connected (via myPrev and myNext) edges
+ std::set< BNode >::iterator bn = bNodes.begin();
+ for ( ; bn != bNodes.end(); ++bn )
+ {
+ for ( size_t i = 0; i < bn->myLinkedEdges.size(); ++i )
+ {
+ if ( bn->myLinkedEdges[i]->myBorderID < 0 )
+ {
+ BEdge* be = bn->myLinkedEdges[i];
+ int borderID = borders.size();
+ borders.push_back( be );
+ for ( ; be && be->myBorderID < 0; be = be->myNext )
+ {
+ be->myBorderID = borderID;
+ be->Orient();
+ }
+ bool isClosed = ( be == bn->myLinkedEdges[i] );
+ if ( !isClosed && theClosedOnly )
+ {
+ borders.pop_back();
+ continue;
+ }
+ be = bn->myLinkedEdges[i]->myPrev;
+ for ( ; be && be->myBorderID < 0; be = be->myPrev )
+ {
+ be->myBorderID = borderID;
+ be->Orient();
+ }
+ if ( !isClosed )
+ while ( borders.back()->myPrev )
+ borders.back() = borders.back()->myPrev;
+ }
+ }
+ }
+ theFoundFreeBordes.resize( borders.size() );
+ for ( size_t i = 0; i < borders.size(); ++i )
+ {
+ TFreeBorder & bordNodes = theFoundFreeBordes[ i ];
+ BEdge* be = borders[i];
+
+ size_t cnt = 1;
+ for ( be = be->myNext; be && be != borders[i]; be = be->myNext )
+ ++cnt;
+ bordNodes.resize( cnt + 1 );
+
+ BEdge* beLast;
+ for ( be = borders[i], cnt = 0;
+ be && cnt < bordNodes.size()-1;
+ be = be->myNext, ++cnt )
+ {
+ bordNodes[ cnt ] = be->myBNode1->Node();
+ beLast = be;
+ }
+ bordNodes.back() = beLast->myBNode2->Node();
+ }
+}
#include "SMDS_VolumeTool.hxx"
#include "SMESH_OctreeNode.hxx"
+#include <Utils_SALOME_Exception.hxx>
+
#include <GC_MakeSegment.hxx>
#include <GeomAPI_ExtremaCurveCurve.hxx>
#include <Geom_Line.hxx>
SMDSAbs_ElementType elemType,
SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(),
double tolerance = NodeRadius );
- void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems );
- void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
- void getElementsInSphere ( const gp_XYZ& center,
- const double radius, TIDSortedElemSet& foundElems);
- size_t getSize() { return std::max( _size, _elements.size() ); }
- virtual ~ElementBndBoxTree();
+ void getElementsNearPoint( const gp_Pnt& point, vector<const SMDS_MeshElement*>& foundElems );
+ void getElementsNearLine ( const gp_Ax1& line, vector<const SMDS_MeshElement*>& foundElems);
+ void getElementsInSphere ( const gp_XYZ& center,
+ const double radius,
+ vector<const SMDS_MeshElement*>& foundElems);
+ ElementBndBoxTree* getLeafAtPoint( const gp_XYZ& point );
protected:
- ElementBndBoxTree():_size(0) {}
+ ElementBndBoxTree() {}
SMESH_Octree* newChild() const { return new ElementBndBoxTree; }
void buildChildrenData();
Bnd_B3d* buildRootBox();
struct ElementBox : public Bnd_B3d
{
const SMDS_MeshElement* _element;
- int _refCount; // an ElementBox can be included in several tree branches
- ElementBox(const SMDS_MeshElement* elem, double tolerance);
+ bool _isMarked;
+ void init(const SMDS_MeshElement* elem, double tolerance);
};
vector< ElementBox* > _elements;
- size_t _size;
+
+ typedef ObjectPool< ElementBox > TElementBoxPool;
+
+ //!< allocator of ElementBox's and SMESH_TreeLimit
+ struct LimitAndPool : public SMESH_TreeLimit
+ {
+ TElementBoxPool _elBoPool;
+ std::vector< ElementBox* > _markedElems;
+ LimitAndPool():SMESH_TreeLimit( MaxLevel, /*minSize=*/0. ), _elBoPool(1024) {}
+ };
+ LimitAndPool* getLimitAndPool() const
+ {
+ SMESH_TreeLimit* limitAndPool = const_cast< SMESH_TreeLimit* >( myLimit );
+ return static_cast< LimitAndPool* >( limitAndPool );
+ }
};
//================================================================================
*/
//================================================================================
- ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
- :SMESH_Octree( new SMESH_TreeLimit( MaxLevel, /*minSize=*/0. ))
+ ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh,
+ SMDSAbs_ElementType elemType,
+ SMDS_ElemIteratorPtr theElemIt,
+ double tolerance)
+ :SMESH_Octree( new LimitAndPool() )
{
int nbElems = mesh.GetMeshInfo().NbElements( elemType );
_elements.reserve( nbElems );
+ TElementBoxPool& elBoPool = getLimitAndPool()->_elBoPool;
+
SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
while ( elemIt->more() )
- _elements.push_back( new ElementBox( elemIt->next(),tolerance ));
-
+ {
+ ElementBox* eb = elBoPool.getNew();
+ eb->init( elemIt->next(), tolerance );
+ _elements.push_back( eb );
+ }
compute();
}
- //================================================================================
- /*!
- * \brief Destructor
- */
- //================================================================================
-
- ElementBndBoxTree::~ElementBndBoxTree()
- {
- for ( size_t i = 0; i < _elements.size(); ++i )
- if ( --_elements[i]->_refCount <= 0 )
- delete _elements[i];
- }
-
//================================================================================
/*!
* \brief Return the maximal box
for (int j = 0; j < 8; j++)
{
if ( !_elements[i]->IsOut( *myChildren[j]->getBox() ))
- {
- _elements[i]->_refCount++;
((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
- }
}
- _elements[i]->_refCount--;
}
- _size = _elements.size();
+ //_size = _elements.size();
SMESHUtils::FreeVector( _elements ); // = _elements.clear() + free memory
for (int j = 0; j < 8; j++)
if ((int) child->_elements.size() <= MaxNbElemsInLeaf )
child->myIsLeaf = true;
- if ( child->_elements.capacity() - child->_elements.size() > 1000 )
+ if ( child->isLeaf() && child->_elements.capacity() > child->_elements.size() )
SMESHUtils::CompactVector( child->_elements );
}
}
*/
//================================================================================
- void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point,
- TIDSortedElemSet& foundElems)
+ void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point,
+ vector<const SMDS_MeshElement*>& foundElems)
{
if ( getBox()->IsOut( point.XYZ() ))
return;
if ( isLeaf() )
{
+ LimitAndPool* pool = getLimitAndPool();
+
for ( size_t i = 0; i < _elements.size(); ++i )
- if ( !_elements[i]->IsOut( point.XYZ() ))
- foundElems.insert( _elements[i]->_element );
+ if ( !_elements[i]->IsOut( point.XYZ() ) &&
+ !_elements[i]->_isMarked )
+ {
+ foundElems.push_back( _elements[i]->_element );
+ _elements[i]->_isMarked = true;
+ pool->_markedElems.push_back( _elements[i] );
+ }
}
else
{
for (int i = 0; i < 8; i++)
((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
+
+ if ( level() == 0 )
+ {
+ LimitAndPool* pool = getLimitAndPool();
+ for ( size_t i = 0; i < pool->_markedElems.size(); ++i )
+ pool->_markedElems[i]->_isMarked = false;
+ pool->_markedElems.clear();
+ }
}
}
*/
//================================================================================
- void ElementBndBoxTree::getElementsNearLine( const gp_Ax1& line,
- TIDSortedElemSet& foundElems)
+ void ElementBndBoxTree::getElementsNearLine( const gp_Ax1& line,
+ vector<const SMDS_MeshElement*>& foundElems)
{
if ( getBox()->IsOut( line ))
return;
if ( isLeaf() )
{
+ LimitAndPool* pool = getLimitAndPool();
+
for ( size_t i = 0; i < _elements.size(); ++i )
- if ( !_elements[i]->IsOut( line ))
- foundElems.insert( _elements[i]->_element );
+ if ( !_elements[i]->IsOut( line ) &&
+ !_elements[i]->_isMarked )
+ {
+ foundElems.push_back( _elements[i]->_element );
+ _elements[i]->_isMarked = true;
+ pool->_markedElems.push_back( _elements[i] );
+ }
}
else
{
for (int i = 0; i < 8; i++)
((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
+
+ if ( level() == 0 )
+ {
+ LimitAndPool* pool = getLimitAndPool();
+ for ( size_t i = 0; i < pool->_markedElems.size(); ++i )
+ pool->_markedElems[i]->_isMarked = false;
+ pool->_markedElems.clear();
+ }
}
}
*/
//================================================================================
- void ElementBndBoxTree::getElementsInSphere ( const gp_XYZ& center,
- const double radius,
- TIDSortedElemSet& foundElems)
+ void ElementBndBoxTree::getElementsInSphere ( const gp_XYZ& center,
+ const double radius,
+ vector<const SMDS_MeshElement*>& foundElems)
{
if ( getBox()->IsOut( center, radius ))
return;
if ( isLeaf() )
{
+ LimitAndPool* pool = getLimitAndPool();
+
for ( size_t i = 0; i < _elements.size(); ++i )
- if ( !_elements[i]->IsOut( center, radius ))
- foundElems.insert( _elements[i]->_element );
+ if ( !_elements[i]->IsOut( center, radius ) &&
+ !_elements[i]->_isMarked )
+ {
+ foundElems.push_back( _elements[i]->_element );
+ _elements[i]->_isMarked = true;
+ pool->_markedElems.push_back( _elements[i] );
+ }
}
else
{
for (int i = 0; i < 8; i++)
((ElementBndBoxTree*) myChildren[i])->getElementsInSphere( center, radius, foundElems );
+
+ if ( level() == 0 )
+ {
+ LimitAndPool* pool = getLimitAndPool();
+ for ( size_t i = 0; i < pool->_markedElems.size(); ++i )
+ pool->_markedElems[i]->_isMarked = false;
+ pool->_markedElems.clear();
+ }
+ }
+ }
+
+ //================================================================================
+ /*!
+ * \brief Return a leaf including a point
+ */
+ //================================================================================
+
+ ElementBndBoxTree* ElementBndBoxTree::getLeafAtPoint( const gp_XYZ& point )
+ {
+ if ( getBox()->IsOut( point ))
+ return 0;
+
+ if ( isLeaf() )
+ {
+ return this;
}
+ else
+ {
+ for (int i = 0; i < 8; i++)
+ if ( ElementBndBoxTree* l = ((ElementBndBoxTree*) myChildren[i])->getLeafAtPoint( point ))
+ return l;
+ }
+ return 0;
}
//================================================================================
*/
//================================================================================
- ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
+ void ElementBndBoxTree::ElementBox::init(const SMDS_MeshElement* elem, double tolerance)
{
_element = elem;
- _refCount = 1;
+ _isMarked = false;
SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
while ( nIt->more() )
- Add( SMESH_TNodeXYZ( nIt->next() ));
+ Add( SMESH_NodeXYZ( nIt->next() ));
Enlarge( tolerance );
}
{
SMDS_Mesh* _mesh;
SMDS_ElemIteratorPtr _meshPartIt;
- ElementBndBoxTree* _ebbTree;
- int _ebbTreeHeight;
+ ElementBndBoxTree* _ebbTree [SMDSAbs_NbElementTypes];
+ int _ebbTreeHeight[SMDSAbs_NbElementTypes];
SMESH_NodeSearcherImpl* _nodeSearcher;
SMDSAbs_ElementType _elementType;
double _tolerance;
SMESH_ElementSearcherImpl( SMDS_Mesh& mesh,
double tol=-1,
SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
- : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_ebbTreeHeight(-1),_nodeSearcher(0),_tolerance(tol),_outerFacesFound(false) {}
+ : _mesh(&mesh),_meshPartIt(elemIt),_nodeSearcher(0),_tolerance(tol),_outerFacesFound(false)
+ {
+ for ( int i = 0; i < SMDSAbs_NbElementTypes; ++i )
+ {
+ _ebbTree[i] = NULL;
+ _ebbTreeHeight[i] = -1;
+ }
+ _elementType = SMDSAbs_All;
+ }
virtual ~SMESH_ElementSearcherImpl()
{
- if ( _ebbTree ) delete _ebbTree; _ebbTree = 0;
+ for ( int i = 0; i < SMDSAbs_NbElementTypes; ++i )
+ {
+ delete _ebbTree[i]; _ebbTree[i] = NULL;
+ }
if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
}
virtual int FindElementsByPoint(const gp_Pnt& point,
virtual const SMDS_MeshElement* FindClosestTo( const gp_Pnt& point,
SMDSAbs_ElementType type );
- void GetElementsNearLine( const gp_Ax1& line,
- SMDSAbs_ElementType type,
- vector< const SMDS_MeshElement* >& foundElems);
- void GetElementsInSphere( const gp_XYZ& center,
- const double radius,
- SMDSAbs_ElementType type,
- vector< const SMDS_MeshElement* >& foundElems);
+ virtual void GetElementsNearLine( const gp_Ax1& line,
+ SMDSAbs_ElementType type,
+ vector< const SMDS_MeshElement* >& foundElems);
+ virtual void GetElementsInSphere( const gp_XYZ& center,
+ const double radius,
+ SMDSAbs_ElementType type,
+ vector< const SMDS_MeshElement* >& foundElems);
+ virtual gp_XYZ Project(const gp_Pnt& point,
+ SMDSAbs_ElementType type,
+ const SMDS_MeshElement** closestElem);
double getTolerance();
bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
const double tolerance, double & param);
}
int getTreeHeight()
{
- if ( _ebbTreeHeight < 0 )
- _ebbTreeHeight = _ebbTree->getHeight();
- return _ebbTreeHeight;
+ if ( _ebbTreeHeight[ _elementType ] < 0 )
+ _ebbTreeHeight[ _elementType ] = _ebbTree[ _elementType ]->getHeight();
+ return _ebbTreeHeight[ _elementType ];
}
struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
double boxSize = _nodeSearcher->getTree()->maxSize();
_tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
}
- else if ( _ebbTree && meshInfo.NbElements() > 0 )
+ else if ( _ebbTree[_elementType] && meshInfo.NbElements() > 0 )
{
- double boxSize = _ebbTree->maxSize();
+ double boxSize = _ebbTree[_elementType]->maxSize();
_tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
}
if ( _tolerance == 0 )
}
else
{
- SMDS_ElemIteratorPtr elemIt =
- _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
+ SMDS_ElemIteratorPtr elemIt = _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
const SMDS_MeshElement* elem = elemIt->next();
- SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
+ SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
SMESH_TNodeXYZ n1( nodeIt->next() );
elemSize = 0;
while ( nodeIt->more() )
anExtCC.Init( lineCurve, edge.Value() );
if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
{
- Quantity_Parameter pl, pe;
+ Standard_Real pl, pe;
anExtCC.LowerDistanceParameters( pl, pe );
param += pl;
if ( ++nbInts == 2 )
outerFace2 = angle2Face.begin()->second;
}
}
- // store the found outer face and add its links to continue seaching from
+ // store the found outer face and add its links to continue searching from
if ( outerFace2 )
{
_outerFaces.insert( outerFace2 );
vector< const SMDS_MeshElement* >& foundElements)
{
foundElements.clear();
+ _elementType = type;
double tolerance = getTolerance();
// =================================================================================
else // elements more complex than 0D
{
- if ( !_ebbTree || _elementType != type )
+ if ( !_ebbTree[type] )
{
- if ( _ebbTree ) delete _ebbTree;
- _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
+ _ebbTree[_elementType] = new ElementBndBoxTree( *_mesh, type, _meshPartIt, tolerance );
}
- TIDSortedElemSet suspectElems;
- _ebbTree->getElementsNearPoint( point, suspectElems );
- TIDSortedElemSet::iterator elem = suspectElems.begin();
+ vector< const SMDS_MeshElement* > suspectElems;
+ _ebbTree[ type ]->getElementsNearPoint( point, suspectElems );
+ vector< const SMDS_MeshElement* >::iterator elem = suspectElems.begin();
for ( ; elem != suspectElems.end(); ++elem )
if ( !SMESH_MeshAlgos::IsOut( *elem, point, tolerance ))
foundElements.push_back( *elem );
SMDSAbs_ElementType type )
{
const SMDS_MeshElement* closestElem = 0;
+ _elementType = type;
- if ( type == SMDSAbs_Face || type == SMDSAbs_Volume )
+ if ( type == SMDSAbs_Face ||
+ type == SMDSAbs_Volume ||
+ type == SMDSAbs_Edge )
{
- if ( !_ebbTree || _elementType != type )
- {
- if ( _ebbTree ) delete _ebbTree;
- _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
- }
- TIDSortedElemSet suspectElems;
- _ebbTree->getElementsNearPoint( point, suspectElems );
+ ElementBndBoxTree*& ebbTree = _ebbTree[ type ];
+ if ( !ebbTree )
+ ebbTree = new ElementBndBoxTree( *_mesh, type, _meshPartIt );
- if ( suspectElems.empty() && _ebbTree->maxSize() > 0 )
+ vector<const SMDS_MeshElement*> suspectElems;
+ ebbTree->getElementsNearPoint( point, suspectElems );
+
+ if ( suspectElems.empty() && ebbTree->maxSize() > 0 )
{
- gp_Pnt boxCenter = 0.5 * ( _ebbTree->getBox()->CornerMin() +
- _ebbTree->getBox()->CornerMax() );
+ gp_Pnt boxCenter = 0.5 * ( ebbTree->getBox()->CornerMin() +
+ ebbTree->getBox()->CornerMax() );
double radius = -1;
- if ( _ebbTree->getBox()->IsOut( point.XYZ() ))
- radius = point.Distance( boxCenter ) - 0.5 * _ebbTree->maxSize();
+ if ( ebbTree->getBox()->IsOut( point.XYZ() ))
+ radius = point.Distance( boxCenter ) - 0.5 * ebbTree->maxSize();
if ( radius < 0 )
- radius = _ebbTree->maxSize() / pow( 2., getTreeHeight()) / 2;
+ radius = ebbTree->maxSize() / pow( 2., getTreeHeight()) / 2;
while ( suspectElems.empty() )
{
- _ebbTree->getElementsInSphere( point.XYZ(), radius, suspectElems );
+ ebbTree->getElementsInSphere( point.XYZ(), radius, suspectElems );
radius *= 1.1;
}
}
double minDist = std::numeric_limits<double>::max();
multimap< double, const SMDS_MeshElement* > dist2face;
- TIDSortedElemSet::iterator elem = suspectElems.begin();
+ vector<const SMDS_MeshElement*>::iterator elem = suspectElems.begin();
for ( ; elem != suspectElems.end(); ++elem )
{
double dist = SMESH_MeshAlgos::GetDistance( *elem, point );
TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
{
+ _elementType = SMDSAbs_Face;
+
double tolerance = getTolerance();
- if ( !_ebbTree || _elementType != SMDSAbs_Face )
- {
- if ( _ebbTree ) delete _ebbTree;
- _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
- }
+
+ ElementBndBoxTree*& ebbTree = _ebbTree[ SMDSAbs_Face ];
+ if ( !ebbTree )
+ ebbTree = new ElementBndBoxTree( *_mesh, _elementType, _meshPartIt );
+
// Algo: analyse transition of a line starting at the point through mesh boundary;
// try three lines parallel to axis of the coordinate system and perform rough
// analysis. If solution is not clear perform thorough analysis.
gp_Ax1 lineAxis( point, axisDir[axis]);
gp_Lin line ( lineAxis );
- TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
- _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
+ vector<const SMDS_MeshElement*> suspectFaces; // faces possibly intersecting the line
+ ebbTree->getElementsNearLine( lineAxis, suspectFaces );
// Intersect faces with the line
map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
- TIDSortedElemSet::iterator face = suspectFaces.begin();
+ vector<const SMDS_MeshElement*>::iterator face = suspectFaces.begin();
for ( ; face != suspectFaces.end(); ++face )
{
// get face plane
SMDSAbs_ElementType type,
vector< const SMDS_MeshElement* >& foundElems)
{
- if ( !_ebbTree || _elementType != type )
- {
- if ( _ebbTree ) delete _ebbTree;
- _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
- }
- TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
- _ebbTree->getElementsNearLine( line, suspectFaces );
- foundElems.assign( suspectFaces.begin(), suspectFaces.end());
+ _elementType = type;
+ ElementBndBoxTree*& ebbTree = _ebbTree[ type ];
+ if ( !ebbTree )
+ ebbTree = new ElementBndBoxTree( *_mesh, _elementType, _meshPartIt );
+
+ ebbTree->getElementsNearLine( line, foundElems );
}
//=======================================================================
SMDSAbs_ElementType type,
vector< const SMDS_MeshElement* >& foundElems)
{
- if ( !_ebbTree || _elementType != type )
+ _elementType = type;
+ ElementBndBoxTree*& ebbTree = _ebbTree[ type ];
+ if ( !ebbTree )
+ ebbTree = new ElementBndBoxTree( *_mesh, _elementType, _meshPartIt );
+
+ ebbTree->getElementsInSphere( center, radius, foundElems );
+}
+
+//=======================================================================
+/*
+ * \brief Return a projection of a given point to a mesh.
+ * Optionally return the closest element
+ */
+//=======================================================================
+
+gp_XYZ SMESH_ElementSearcherImpl::Project(const gp_Pnt& point,
+ SMDSAbs_ElementType type,
+ const SMDS_MeshElement** closestElem)
+{
+ _elementType = type;
+ if ( _mesh->GetMeshInfo().NbElements( _elementType ) == 0 )
+ throw SALOME_Exception( LOCALIZED( "No elements of given type in the mesh" ));
+
+ ElementBndBoxTree*& ebbTree = _ebbTree[ _elementType ];
+ if ( !ebbTree )
+ ebbTree = new ElementBndBoxTree( *_mesh, _elementType );
+
+ gp_XYZ p = point.XYZ();
+ ElementBndBoxTree* ebbLeaf = ebbTree->getLeafAtPoint( p );
+ const Bnd_B3d* box = ebbLeaf->getBox();
+ double radius = ( box->CornerMax() - box->CornerMin() ).Modulus();
+
+ vector< const SMDS_MeshElement* > elems;
+ ebbTree->getElementsInSphere( p, radius, elems );
+ while ( elems.empty() )
{
- if ( _ebbTree ) delete _ebbTree;
- _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
+ radius *= 1.5;
+ ebbTree->getElementsInSphere( p, radius, elems );
}
- TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
- _ebbTree->getElementsInSphere( center, radius, suspectFaces );
- foundElems.assign( suspectFaces.begin(), suspectFaces.end() );
+ gp_XYZ proj, bestProj;
+ const SMDS_MeshElement* elem = 0;
+ double minDist = 2 * radius;
+ for ( size_t i = 0; i < elems.size(); ++i )
+ {
+ double d = SMESH_MeshAlgos::GetDistance( elems[i], p, &proj );
+ if ( d < minDist )
+ {
+ bestProj = proj;
+ elem = elems[i];
+ minDist = d;
+ }
+ }
+ if ( closestElem ) *closestElem = elem;
+
+ return bestProj;
}
//=======================================================================
gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
faceNorm += edge1 ^ edge2;
}
- double normSize = faceNorm.Magnitude();
- if ( normSize <= tol )
+ double fNormSize = faceNorm.Magnitude();
+ if ( fNormSize <= tol )
{
// degenerated face: point is out if it is out of all face edges
for ( i = 0; i < nbNodes; ++i )
}
return true;
}
- faceNorm /= normSize;
+ faceNorm /= fNormSize;
// check if the point lays on face plane
gp_Vec n2p( xyz[0], point );
// to find intersections of the ray with the boundary.
gp_Vec ray = n2p;
gp_Vec plnNorm = ray ^ faceNorm;
- normSize = plnNorm.Magnitude();
- if ( normSize <= tol ) return false; // point coincides with the first node
- plnNorm /= normSize;
+ double n2pSize = plnNorm.Magnitude();
+ if ( n2pSize <= tol ) return false; // point coincides with the first node
+ if ( n2pSize * n2pSize > fNormSize * 100 ) return true; // point is very far
+ plnNorm /= n2pSize;
// for each node of the face, compute its signed distance to the cutting plane
vector<double> dist( nbNodes + 1);
for ( i = 0; i < nbNodes; ++i )
if ( rClosest > 0. && rClosest < 1. ) // not node intersection
return out;
- // ray pass through a face node; analyze transition through an adjacent edge
+ // the ray passes through a face node; analyze transition through an adjacent edge
gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
gp_Vec edgeAdjacent( p1, p2 );
//=======================================================================
double SMESH_MeshAlgos::GetDistance( const SMDS_MeshElement* elem,
- const gp_Pnt& point )
+ const gp_Pnt& point,
+ gp_XYZ* closestPnt )
{
switch ( elem->GetType() )
{
case SMDSAbs_Volume:
- return GetDistance( dynamic_cast<const SMDS_MeshVolume*>( elem ), point);
+ return GetDistance( dynamic_cast<const SMDS_MeshVolume*>( elem ), point, closestPnt );
case SMDSAbs_Face:
- return GetDistance( dynamic_cast<const SMDS_MeshFace*>( elem ), point);
+ return GetDistance( dynamic_cast<const SMDS_MeshFace*>( elem ), point, closestPnt );
case SMDSAbs_Edge:
- return GetDistance( dynamic_cast<const SMDS_MeshEdge*>( elem ), point);
+ return GetDistance( dynamic_cast<const SMDS_MeshEdge*>( elem ), point, closestPnt );
case SMDSAbs_Node:
+ if ( closestPnt ) *closestPnt = SMESH_TNodeXYZ( elem );
return point.Distance( SMESH_TNodeXYZ( elem ));
default:;
}
//=======================================================================
double SMESH_MeshAlgos::GetDistance( const SMDS_MeshFace* face,
- const gp_Pnt& point )
+ const gp_Pnt& point,
+ gp_XYZ* closestPnt )
{
- double badDistance = -1;
+ const double badDistance = -1;
if ( !face ) return badDistance;
// coordinates of nodes (medium nodes, if any, ignored)
trsf.Transforms( tmpPnt );
gp_XY point2D( tmpPnt.X(), tmpPnt.Z() );
- // loop on segments of the face to analyze point position ralative to the face
+ // loop on edges of the face to analyze point position ralative to the face
set< PointPos > pntPosSet;
for ( size_t i = 1; i < xy.size(); ++i )
{
// compute distance
PointPos pos = *pntPosSet.begin();
- // cout << "Face " << face->GetID() << " DIST: ";
switch ( pos._name )
{
- case POS_LEFT: {
- // point is most close to a segment
- gp_Vec p0p1( point, xyz[ pos._index ] );
- gp_Vec p1p2( xyz[ pos._index ], xyz[ pos._index+1 ]); // segment vector
- p1p2.Normalize();
- double projDist = p0p1 * p1p2; // distance projected to the segment
- gp_Vec projVec = p1p2 * projDist;
- gp_Vec distVec = p0p1 - projVec;
- // cout << distVec.Magnitude() << ", SEG " << face->GetNode(pos._index)->GetID()
- // << " - " << face->GetNodeWrap(pos._index+1)->GetID() << endl;
- return distVec.Magnitude();
+ case POS_LEFT:
+ {
+ // point is most close to an edge
+ gp_Vec edge( xyz[ pos._index ], xyz[ pos._index+1 ]);
+ gp_Vec n1p ( xyz[ pos._index ], point );
+ double u = ( edge * n1p ) / edge.SquareMagnitude(); // param [0,1] on the edge
+ // projection of the point on the edge
+ gp_XYZ proj = ( 1. - u ) * xyz[ pos._index ] + u * xyz[ pos._index+1 ];
+ if ( closestPnt ) *closestPnt = proj;
+ return point.Distance( proj );
}
- case POS_RIGHT: {
+ case POS_RIGHT:
+ {
// point is inside the face
- double distToFacePlane = tmpPnt.Y();
- // cout << distToFacePlane << ", INSIDE " << endl;
- return Abs( distToFacePlane );
+ double distToFacePlane = Abs( tmpPnt.Y() );
+ if ( closestPnt )
+ {
+ if ( distToFacePlane < std::numeric_limits<double>::min() ) {
+ *closestPnt = point.XYZ();
+ }
+ else {
+ tmpPnt.SetY( 0 );
+ trsf.Inverted().Transforms( tmpPnt );
+ *closestPnt = tmpPnt;
+ }
+ }
+ return distToFacePlane;
}
- case POS_VERTEX: {
+ case POS_VERTEX:
+ {
// point is most close to a node
gp_Vec distVec( point, xyz[ pos._index ]);
- // cout << distVec.Magnitude() << " VERTEX " << face->GetNode(pos._index)->GetID() << endl;
return distVec.Magnitude();
}
default:;
*/
//=======================================================================
-double SMESH_MeshAlgos::GetDistance( const SMDS_MeshEdge* seg, const gp_Pnt& point )
+double SMESH_MeshAlgos::GetDistance( const SMDS_MeshEdge* seg,
+ const gp_Pnt& point,
+ gp_XYZ* closestPnt )
{
double dist = Precision::Infinite();
if ( !seg ) return dist;
{
gp_Vec edge( xyz[i-1], xyz[i] );
gp_Vec n1p ( xyz[i-1], point );
- double u = ( edge * n1p ) / edge.SquareMagnitude(); // param [0,1] on the edge
+ double d, u = ( edge * n1p ) / edge.SquareMagnitude(); // param [0,1] on the edge
if ( u <= 0. ) {
- dist = Min( dist, n1p.SquareMagnitude() );
+ if (( d = n1p.SquareMagnitude() ) < dist ) {
+ dist = d;
+ if ( closestPnt ) *closestPnt = xyz[i-1];
+ }
}
else if ( u >= 1. ) {
- dist = Min( dist, point.SquareDistance( xyz[i] ));
+ if (( d = point.SquareDistance( xyz[i] )) < dist ) {
+ dist = d;
+ if ( closestPnt ) *closestPnt = xyz[i];
+ }
}
else {
- gp_XYZ proj = ( 1. - u ) * xyz[i-1] + u * xyz[i]; // projection of the point on the edge
- dist = Min( dist, point.SquareDistance( proj ));
+ gp_XYZ proj = xyz[i-1] + u * edge.XYZ(); // projection of the point on the edge
+ if (( d = point.SquareDistance( proj )) < dist ) {
+ dist = d;
+ if ( closestPnt ) *closestPnt = proj;
+ }
}
}
return Sqrt( dist );
*/
//=======================================================================
-double SMESH_MeshAlgos::GetDistance( const SMDS_MeshVolume* volume, const gp_Pnt& point )
+double SMESH_MeshAlgos::GetDistance( const SMDS_MeshVolume* volume,
+ const gp_Pnt& point,
+ gp_XYZ* closestPnt )
{
SMDS_VolumeTool vTool( volume );
vTool.SetExternalNormal();
double n[3], bc[3];
double minDist = 1e100, dist;
+ gp_XYZ closeP = point.XYZ();
+ bool isOut = false;
for ( int iF = 0; iF < vTool.NbFaces(); ++iF )
{
// skip a facet with normal not "looking at" the point
case 3:
{
SMDS_FaceOfNodes tmpFace( nodes[0], nodes[ 1*iQ ], nodes[ 2*iQ ] );
- dist = GetDistance( &tmpFace, point );
+ dist = GetDistance( &tmpFace, point, closestPnt );
break;
}
case 4:
{
SMDS_FaceOfNodes tmpFace( nodes[0], nodes[ 1*iQ ], nodes[ 2*iQ ], nodes[ 3*iQ ]);
- dist = GetDistance( &tmpFace, point );
+ dist = GetDistance( &tmpFace, point, closestPnt );
break;
}
default:
vector<const SMDS_MeshNode *> nvec( nodes, nodes + vTool.NbFaceNodes( iF ));
SMDS_PolygonalFaceOfNodes tmpFace( nvec );
- dist = GetDistance( &tmpFace, point );
+ dist = GetDistance( &tmpFace, point, closestPnt );
}
- minDist = Min( minDist, dist );
+ if ( dist < minDist )
+ {
+ minDist = dist;
+ isOut = true;
+ if ( closestPnt ) closeP = *closestPnt;
+ }
+ }
+ if ( isOut )
+ {
+ if ( closestPnt ) *closestPnt = closeP;
+ return minDist;
}
- return minDist;
+
+ return 0; // point is inside the volume
}
//================================================================================
common.push_back( e1->GetNode( i ));
return common;
}
+//================================================================================
+/*!
+ * \brief Return true if node1 encounters first in the face and node2, after
+ */
+//================================================================================
+
+bool SMESH_MeshAlgos::IsRightOrder( const SMDS_MeshElement* face,
+ const SMDS_MeshNode* node0,
+ const SMDS_MeshNode* node1 )
+{
+ int i0 = face->GetNodeIndex( node0 );
+ int i1 = face->GetNodeIndex( node1 );
+ if ( face->IsQuadratic() )
+ {
+ if ( face->IsMediumNode( node0 ))
+ {
+ i0 -= ( face->NbNodes()/2 - 1 );
+ i1 *= 2;
+ }
+ else
+ {
+ i1 -= ( face->NbNodes()/2 - 1 );
+ i0 *= 2;
+ }
+ }
+ int diff = i1 - i0;
+ return ( diff == 1 ) || ( diff == -face->NbNodes()+1 );
+}
//=======================================================================
/*!
* \brief Find out if the given point is out of closed 2D mesh.
*/
virtual TopAbs_State GetPointState(const gp_Pnt& point) = 0;
+
+ /*!
+ * \brief Return a projection of a given point to a 2D mesh.
+ * Optionally return the closest face
+ */
+ virtual gp_XYZ Project(const gp_Pnt& point,
+ SMDSAbs_ElementType type,
+ const SMDS_MeshElement** closestFace= 0) = 0;
+
virtual ~SMESH_ElementSearcher();
};
bool IsOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol );
SMESHUtils_EXPORT
- double GetDistance( const SMDS_MeshElement* elem, const gp_Pnt& point );
+ double GetDistance( const SMDS_MeshElement* elem, const gp_Pnt& point, gp_XYZ* closestPnt = 0 );
SMESHUtils_EXPORT
- double GetDistance( const SMDS_MeshEdge* edge, const gp_Pnt& point );
+ double GetDistance( const SMDS_MeshEdge* edge, const gp_Pnt& point, gp_XYZ* closestPnt = 0 );
SMESHUtils_EXPORT
- double GetDistance( const SMDS_MeshFace* face, const gp_Pnt& point );
+ double GetDistance( const SMDS_MeshFace* face, const gp_Pnt& point, gp_XYZ* closestPnt = 0 );
SMESHUtils_EXPORT
- double GetDistance( const SMDS_MeshVolume* volume, const gp_Pnt& point );
+ double GetDistance( const SMDS_MeshVolume* volume, const gp_Pnt& point, gp_XYZ* closestPnt = 0 );
SMESHUtils_EXPORT
void GetBarycentricCoords( const gp_XY& point,
SMESHUtils_EXPORT
std::vector< const SMDS_MeshNode*> GetCommonNodes(const SMDS_MeshElement* e1,
const SMDS_MeshElement* e2);
+ /*!
+ * \brief Return true if node1 encounters first in the face and node2, after.
+ * The nodes are supposed to be neighbor nodes in the face.
+ */
+ SMESHUtils_EXPORT
+ bool IsRightOrder( const SMDS_MeshElement* face,
+ const SMDS_MeshNode* node0,
+ const SMDS_MeshNode* node1 );
/*!
* \brief Return SMESH_NodeSearcher. The caller is responsible for deleteing it
void FindCoincidentFreeBorders(SMDS_Mesh& mesh,
double tolerance,
CoincidentFreeBorders & foundFreeBordes);
-
+ /*!
+ * Returns all or only closed TFreeBorder's.
+ * Optionally check if the mesh is manifold and if faces are correctly oriented.
+ *
+ * (Implemented in ./SMESH_FreeBorders.cxx)
+ */
+ SMESHUtils_EXPORT
+ void FindFreeBorders(SMDS_Mesh& mesh,
+ TFreeBorderVec & foundFreeBordes,
+ const bool closedOnly,
+ bool* isManifold = 0,
+ bool* isGoodOri = 0);
+ /*!
+ * Fill a hole defined by a TFreeBorder with 2D elements.
+ *
+ * (Implemented in ./SMESH_FillHole.cxx)
+ */
+ SMESHUtils_EXPORT
+ void FillHole(const TFreeBorder & freeBorder,
+ SMDS_Mesh& mesh,
+ std::vector<const SMDS_MeshElement*>& newFaces);
+
} // SMESH_MeshAlgos
// - FT_BelongToMeshGroup = 22
// v 8.1.0: FT_Undefined == 48, new items:
// - FT_NodeConnectivityNumber= 22
+ // v 8.5.0: FT_Undefined == 49, new items:
+ // - FT_Deflection2D = 22
//
// It's necessary to continue recording this history and to fill
// undef2newItems (see below) accordingly.
undef2newItems[ 46 ].push_back( 39 );
undef2newItems[ 47 ].push_back( 22 );
undef2newItems[ 48 ].push_back( 22 );
+ undef2newItems[ 49 ].push_back( 22 );
ASSERT( undef2newItems.rbegin()->first == SMESH::FT_Undefined );
}
"ExtrusionAlongPathX","ExtrusionAlongPathObject1D","ExtrusionAlongPathObject2D",
"ExtrusionSweepObjects","RotationSweepObjects","ExtrusionAlongPathObjects",
"Mirror","MirrorObject","Translate","TranslateObject","Rotate","RotateObject",
- "FindCoincidentNodes","MergeNodes","FindEqualElements",
+ "FindCoincidentNodes","MergeNodes","FindEqualElements","FillHole",
"MergeElements","MergeEqualElements","SewFreeBorders","SewConformFreeBorders",
"FindCoincidentFreeBorders", "SewCoincidentFreeBorders",
"SewBorderToSide","SewSideElements","ChangeElemNodes","GetLastCreatedNodes",
case FT_MultiConnection2D: myStream<< "aMultiConnection2D"; break;
case FT_Length: myStream<< "aLength"; break;
case FT_Length2D: myStream<< "aLength2D"; break;
+ case FT_Deflection2D: myStream<< "aDeflection2D"; break;
case FT_NodeConnectivityNumber:myStream<< "aNodeConnectivityNumber";break;
case FT_BelongToMeshGroup: myStream<< "aBelongToMeshGroup"; break;
case FT_BelongToGeom: myStream<< "aBelongToGeom"; break;
return aResult._retn();
}
+/*
+ Class : Deflection2D_i
+ Description : Functor for calculating distance between a face and geometry
+*/
+Deflection2D_i::Deflection2D_i()
+{
+ myNumericalFunctorPtr.reset( new Controls::Deflection2D() );
+ myFunctorPtr = myNumericalFunctorPtr;
+}
+
+FunctorType Deflection2D_i::GetFunctorType()
+{
+ return SMESH::FT_Deflection2D;
+}
+
/*
Class : MultiConnection_i
Description : Functor for calculating number of faces conneted to the edge
return anObj._retn();
}
+Deflection2D_ptr FilterManager_i::CreateDeflection2D()
+{
+ SMESH::Deflection2D_i* aServant = new SMESH::Deflection2D_i();
+ SMESH::Deflection2D_var anObj = aServant->_this();
+ TPythonDump()<<aServant<<" = "<<this<<".CreateLength2D()";
+ return anObj._retn();
+}
+
MultiConnection_ptr FilterManager_i::CreateMultiConnection()
{
SMESH::MultiConnection_i* aServant = new SMESH::MultiConnection_i();
case SMESH::FT_Length2D:
aFunctor = aFilterMgr->CreateLength2D();
break;
+ case SMESH::FT_Deflection2D:
+ aFunctor = aFilterMgr->CreateDeflection2D();
+ break;
case SMESH::FT_AspectRatio:
aFunctor = aFilterMgr->CreateAspectRatio();
break;
case FT_EqualFaces : return "Equal faces";
case FT_EqualVolumes : return "Equal volumes";
case FT_MultiConnection : return "Borders at multi-connections";
- case FT_MultiConnection2D :return "Borders at multi-connections 2D";
+ case FT_MultiConnection2D : return "Borders at multi-connections 2D";
case FT_Length : return "Length";
case FT_Length2D : return "Length 2D";
+ case FT_Deflection2D : return "Deflection 2D";
case FT_LessThan : return "Less than";
case FT_MoreThan : return "More than";
case FT_EqualTo : return "Equal to";
// else if ( theStr.equals( "Borders at multi-connections 2D" ) ) return FT_MultiConnection2D;
else if ( theStr.equals( "Length" ) ) return FT_Length;
// else if ( theStr.equals( "Length2D" ) ) return FT_Length2D;
+ else if ( theStr.equals( "Deflection" ) ) return FT_Deflection2D;
else if ( theStr.equals( "Range of IDs" ) ) return FT_RangeOfIds;
else if ( theStr.equals( "Bad Oriented Volume" ) ) return FT_BadOrientedVolume;
else if ( theStr.equals( "Volumes with bare border" ) ) return FT_BareBorderVolume;
"FT_MultiConnection2D",
"FT_Length",
"FT_Length2D",
+ "FT_Deflection2D",
"FT_NodeConnectivityNumber",
"FT_BelongToMeshGroup",
"FT_BelongToGeom",
"FT_LinearOrQuadratic",
"FT_GroupColor",
"FT_ElemGeomType",
- "FT_EntityType",
+ "FT_EntityType",
"FT_CoplanarFaces",
"FT_BallDiameter",
"FT_ConnectedElements",
Length2D_i();
SMESH::Length2D::Values* GetValues();
FunctorType GetFunctorType();
-
+
protected:
Controls::Length2DPtr myLength2DPtr;
};
-
+
+ /*
+ Class : Deflection2D_i
+ Description : Functor for calculating distance between a face and geometry
+ */
+ class SMESH_I_EXPORT Deflection2D_i: public virtual POA_SMESH::Deflection2D,
+ public virtual NumericalFunctor_i
+ {
+ public:
+ Deflection2D_i();
+ FunctorType GetFunctorType();
+ };
+
/*
Class : MultiConnection_i
Description : Functor for calculating number of faces conneted to the edge
MaxElementLength3D_ptr CreateMaxElementLength3D();
Length_ptr CreateLength();
Length2D_ptr CreateLength2D();
+ Deflection2D_ptr CreateDeflection2D();
NodeConnectivityNumber_ptr CreateNodeConnectivityNumber();
MultiConnection_ptr CreateMultiConnection();
MultiConnection2D_ptr CreateMultiConnection2D();
// and then "GetGroups" using SMESH_Mesh::GetGroups()
TPythonDump pydump; // to prevent dump at mesh creation
- mesh = makeMesh( theMeshName );
+ mesh = makeMesh( theMeshName );
mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
if ( mesh_i )
return 0;
}
+//=======================================================================
+//function : IsManifold
+//purpose : Check if a 2D mesh is manifold
+//=======================================================================
+
+CORBA::Boolean SMESH_MeshEditor_i::IsManifold()
+ throw (SALOME::SALOME_Exception)
+{
+ bool isManifold = true;
+
+ SMESH_TRY;
+ SMESH_MeshAlgos::TFreeBorderVec foundFreeBordes;
+ SMESH_MeshAlgos::FindFreeBorders( *getMeshDS(),
+ foundFreeBordes,
+ /*closedOnly=*/true,
+ &isManifold );
+ SMESH_CATCH( SMESH::throwCorbaException );
+
+ return isManifold;
+}
+
+//=======================================================================
+//function : IsCoherentOrientation2D
+//purpose : Check if orientation of 2D elements is coherent
+//=======================================================================
+
+CORBA::Boolean SMESH_MeshEditor_i::IsCoherentOrientation2D()
+ throw (SALOME::SALOME_Exception)
+{
+ bool isGoodOri = true;
+
+ SMESH_TRY;
+ SMESH_MeshAlgos::TFreeBorderVec foundFreeBordes;
+ SMESH_MeshAlgos::FindFreeBorders( *getMeshDS(),
+ foundFreeBordes,
+ /*closedOnly=*/true,
+ /*isManifold=*/0,
+ &isGoodOri);
+ SMESH_CATCH( SMESH::throwCorbaException );
+
+ return isGoodOri;
+}
+
+//=======================================================================
+//function : FindFreeBorders
+//purpose : Returns all or only closed FreeBorder's.
+//=======================================================================
+
+SMESH::ListOfFreeBorders* SMESH_MeshEditor_i::FindFreeBorders(CORBA::Boolean closedOnly)
+ throw (SALOME::SALOME_Exception)
+{
+ SMESH::ListOfFreeBorders_var resBorders = new SMESH::ListOfFreeBorders;
+ SMESH_TRY;
+
+ SMESH_MeshAlgos::TFreeBorderVec foundFreeBordes;
+ SMESH_MeshAlgos::FindFreeBorders( *getMeshDS(), foundFreeBordes, closedOnly );
+
+ resBorders->length( foundFreeBordes.size() );
+ for ( size_t i = 0; i < foundFreeBordes.size(); ++i )
+ {
+ const SMESH_MeshAlgos::TFreeBorder& bordNodes = foundFreeBordes[i];
+ SMESH::FreeBorder& bordOut = resBorders[i];
+ bordOut.nodeIDs.length( bordNodes.size() );
+ for ( size_t iN = 0; iN < bordNodes.size(); ++iN )
+ bordOut.nodeIDs[ iN ] = bordNodes[ iN ]->GetID();
+ }
+
+ SMESH_CATCH( SMESH::throwCorbaException );
+
+ return resBorders._retn();
+}
+
+//=======================================================================
+//function : FillHole
+//purpose : Fill with 2D elements a hole defined by a FreeBorder.
+//=======================================================================
+
+void SMESH_MeshEditor_i::FillHole(const SMESH::FreeBorder& theHole)
+ throw (SALOME::SALOME_Exception)
+{
+ initData();
+
+ if ( theHole.nodeIDs.length() < 4 )
+ THROW_SALOME_CORBA_EXCEPTION("A hole should be bound by at least 3 nodes", SALOME::BAD_PARAM);
+ if ( theHole.nodeIDs[0] != theHole.nodeIDs[ theHole.nodeIDs.length()-1 ] )
+ THROW_SALOME_CORBA_EXCEPTION("Not closed hole boundary. "
+ "First and last nodes must be same", SALOME::BAD_PARAM);
+
+ SMESH_MeshAlgos::TFreeBorder bordNodes;
+ bordNodes.resize( theHole.nodeIDs.length() );
+ for ( size_t iN = 0; iN < theHole.nodeIDs.length(); ++iN )
+ {
+ bordNodes[ iN ] = getMeshDS()->FindNode( theHole.nodeIDs[ iN ]);
+ if ( !bordNodes[ iN ] )
+ THROW_SALOME_CORBA_EXCEPTION(SMESH_Comment("Node #") << theHole.nodeIDs[ iN ]
+ << " does not exist", SALOME::BAD_PARAM);
+ }
+
+ SMESH_TRY;
+
+ MeshEditor_I::TPreviewMesh* previewMesh = 0;
+ SMDS_Mesh* meshDS = getMeshDS();
+ if ( myIsPreviewMode )
+ {
+ // copy faces sharing nodes of theHole
+ TIDSortedElemSet holeFaces;
+ previewMesh = getPreviewMesh( SMDSAbs_Face );
+ for ( size_t i = 0; i < bordNodes.size(); ++i )
+ {
+ SMDS_ElemIteratorPtr fIt = bordNodes[i]->GetInverseElementIterator( SMDSAbs_Face );
+ while ( fIt->more() )
+ {
+ const SMDS_MeshElement* face = fIt->next();
+ if ( holeFaces.insert( face ).second )
+ previewMesh->Copy( face );
+ }
+ bordNodes[i] = previewMesh->GetMeshDS()->FindNode( bordNodes[i]->GetID() );
+ ASSERT( bordNodes[i] );
+ }
+ meshDS = previewMesh->GetMeshDS();
+ }
+
+ std::vector<const SMDS_MeshElement*> newFaces;
+ SMESH_MeshAlgos::FillHole( bordNodes, *meshDS, newFaces );
+
+ if ( myIsPreviewMode )
+ {
+ previewMesh->Clear();
+ for ( size_t i = 0; i < newFaces.size(); ++i )
+ previewMesh->Copy( newFaces[i] );
+ }
+ else
+ {
+ getEditor().ClearLastCreated();
+ SMESH_SequenceOfElemPtr& aSeq =
+ const_cast<SMESH_SequenceOfElemPtr&>( getEditor().GetLastCreatedElems() );
+ for ( size_t i = 0; i < newFaces.size(); ++i )
+ aSeq.Append( newFaces[i] );
+
+ TPythonDump() << this << ".FillHole( SMESH.FreeBorder(" << theHole.nodeIDs << " ))";
+ }
+
+ SMESH_CATCH( SMESH::throwCorbaException );
+}
+
//=======================================================================
//function : convError
//purpose :
SMESH::ElementType type)
throw (SALOME::SALOME_Exception);
/*!
- * Searching among the given elements, return elements of given type
+ * Searching among the given elements, return elements of given type
* where the given point is IN or ON.
* 'ALL' type means elements of any type excluding nodes
*/
CORBA::Short GetPointState(CORBA::Double x, CORBA::Double y, CORBA::Double z)
throw (SALOME::SALOME_Exception);
+ /*!
+ * Check if a 2D mesh is manifold
+ */
+ CORBA::Boolean IsManifold()
+ throw (SALOME::SALOME_Exception);
+
+ /*!
+ * Check if orientation of 2D elements is coherent
+ */
+ CORBA::Boolean IsCoherentOrientation2D()
+ throw (SALOME::SALOME_Exception);
+
+ /*!
+ * Returns all or only closed FreeBorder's.
+ */
+ SMESH::ListOfFreeBorders* FindFreeBorders(CORBA::Boolean closedOnly)
+ throw (SALOME::SALOME_Exception);
+
+ /*!
+ * Fill with 2D elements a hole defined by a FreeBorder.
+ */
+ void FillHole(const SMESH::FreeBorder& hole)
+ throw (SALOME::SALOME_Exception);
+
SMESH::CoincidentFreeBorders* FindCoincidentFreeBorders(CORBA::Double tolerance);
CORBA::Short SewCoincidentFreeBorders(const SMESH::CoincidentFreeBorders& freeBorders,
CORBA::Boolean createPolygons,
throw (SALOME::SALOME_Exception);
SMESH::SMESH_MeshEditor::Sew_Error
- SewFreeBorders(CORBA::Long FirstNodeID1,
- CORBA::Long SecondNodeID1,
- CORBA::Long LastNodeID1,
- CORBA::Long FirstNodeID2,
- CORBA::Long SecondNodeID2,
- CORBA::Long LastNodeID2,
- CORBA::Boolean CreatePolygons,
- CORBA::Boolean CreatePolyedrs) throw (SALOME::SALOME_Exception);
+ SewFreeBorders(CORBA::Long FirstNodeID1,
+ CORBA::Long SecondNodeID1,
+ CORBA::Long LastNodeID1,
+ CORBA::Long FirstNodeID2,
+ CORBA::Long SecondNodeID2,
+ CORBA::Long LastNodeID2,
+ CORBA::Boolean CreatePolygons,
+ CORBA::Boolean CreatePolyedrs) throw (SALOME::SALOME_Exception);
SMESH::SMESH_MeshEditor::Sew_Error
- SewConformFreeBorders(CORBA::Long FirstNodeID1,
- CORBA::Long SecondNodeID1,
- CORBA::Long LastNodeID1,
- CORBA::Long FirstNodeID2,
- CORBA::Long SecondNodeID2) throw (SALOME::SALOME_Exception);
+ SewConformFreeBorders(CORBA::Long FirstNodeID1,
+ CORBA::Long SecondNodeID1,
+ CORBA::Long LastNodeID1,
+ CORBA::Long FirstNodeID2,
+ CORBA::Long SecondNodeID2) throw (SALOME::SALOME_Exception);
SMESH::SMESH_MeshEditor::Sew_Error
- SewBorderToSide(CORBA::Long FirstNodeIDOnFreeBorder,
- CORBA::Long SecondNodeIDOnFreeBorder,
- CORBA::Long LastNodeIDOnFreeBorder,
- CORBA::Long FirstNodeIDOnSide,
- CORBA::Long LastNodeIDOnSide,
- CORBA::Boolean CreatePolygons,
- CORBA::Boolean CreatePolyedrs) throw (SALOME::SALOME_Exception);
+ SewBorderToSide(CORBA::Long FirstNodeIDOnFreeBorder,
+ CORBA::Long SecondNodeIDOnFreeBorder,
+ CORBA::Long LastNodeIDOnFreeBorder,
+ CORBA::Long FirstNodeIDOnSide,
+ CORBA::Long LastNodeIDOnSide,
+ CORBA::Boolean CreatePolygons,
+ CORBA::Boolean CreatePolyedrs) throw (SALOME::SALOME_Exception);
SMESH::SMESH_MeshEditor::Sew_Error
- SewSideElements(const SMESH::long_array& IDsOfSide1Elements,
- const SMESH::long_array& IDsOfSide2Elements,
- CORBA::Long NodeID1OfSide1ToMerge,
- CORBA::Long NodeID1OfSide2ToMerge,
- CORBA::Long NodeID2OfSide1ToMerge,
- CORBA::Long NodeID2OfSide2ToMerge) throw (SALOME::SALOME_Exception);
+ SewSideElements(const SMESH::long_array& IDsOfSide1Elements,
+ const SMESH::long_array& IDsOfSide2Elements,
+ CORBA::Long NodeID1OfSide1ToMerge,
+ CORBA::Long NodeID1OfSide2ToMerge,
+ CORBA::Long NodeID2OfSide1ToMerge,
+ CORBA::Long NodeID2OfSide2ToMerge) throw (SALOME::SALOME_Exception);
/*!
* Set new nodes for given element.
functor = aFilterMgr.CreateLength()
elif theCriterion == FT_Length2D:
functor = aFilterMgr.CreateLength2D()
+ elif theCriterion == FT_Deflection2D:
+ functor = aFilterMgr.CreateDeflection2D()
elif theCriterion == FT_NodeConnectivityNumber:
functor = aFilterMgr.CreateNodeConnectivityNumber()
elif theCriterion == FT_BallDiameter:
def GetPointState(self, x, y, z):
return self.editor.GetPointState(x, y, z)
+ ## Check if a 2D mesh is manifold
+ # @ingroup l1_controls
+ def IsManifold(self):
+ return self.editor.IsManifold()
+
+ ## Check if orientation of 2D elements is coherent
+ # @ingroup l1_controls
+ def IsCoherentOrientation2D(self):
+ return self.editor.IsCoherentOrientation2D()
+
## Finds the node closest to a point and moves it to a point location
# @param x the X coordinate of a point
# @param y the Y coordinate of a point
def MergeEqualElements(self):
self.editor.MergeEqualElements()
+ ## Returns all or only closed free borders
+ # @return list of SMESH.FreeBorder's
+ # @ingroup l2_modif_trsf
+ def FindFreeBorders(self, ClosedOnly=True):
+ return self.editor.FindFreeBorders( ClosedOnly )
+
+ ## Fill with 2D elements a hole defined by a SMESH.FreeBorder.
+ # @param FreeBorder either a SMESH.FreeBorder or a list on node IDs. These nodes
+ # must describe all sequential nodes of the hole border. The first and the last
+ # nodes must be the same. Use FindFreeBorders() to get nodes of holes.
+ # @ingroup l2_modif_trsf
+ def FillHole(self, holeNodes):
+ if holeNodes and isinstance( holeNodes, list ) and isinstance( holeNodes[0], int ):
+ holeNodes = SMESH.FreeBorder(nodeIDs=holeNodes)
+ if not isinstance( holeNodes, SMESH.FreeBorder ):
+ raise TypeError, "holeNodes must be either SMESH.FreeBorder or list of integer and not %s" % holeNodes
+ self.editor.FillHole( holeNodes )
+
## Returns groups of FreeBorder's coincident within the given tolerance.
# @param tolerance the tolerance. If the tolerance <= 0.0 then one tenth of an average
# size of elements adjacent to free borders being compared is used.
def CreateHoleSkin(self, radius, theShape, groupName, theNodesCoords):
return self.editor.CreateHoleSkin( radius, theShape, groupName, theNodesCoords )
- def _getFunctor(self, funcType ):
+ ## Return a cached numerical functor by its type.
+ # @param theCriterion functor type - an item of SMESH.FunctorType enumeration.
+ # Type SMESH.FunctorType._items in the Python Console to see all items.
+ # Note that not all items correspond to numerical functors.
+ # @return SMESH_NumericalFunctor. The functor is already initialized
+ # with a mesh
+ # @ingroup l1_measurements
+ def GetFunctor(self, funcType ):
fn = self.functors[ funcType._v ]
if not fn:
fn = self.smeshpyD.GetFunctor(funcType)
# @param isElem @a elemId is ID of element or node
# @return the functor value or zero in case of invalid arguments
def FunctorValue(self, funcType, elemId, isElem=True):
- fn = self._getFunctor( funcType )
+ fn = self.GetFunctor( funcType )
if fn.GetElementType() == self.GetElementType(elemId, isElem):
val = fn.GetValue(elemId)
else:
unRegister.set( meshPart )
if isinstance( meshPart, Mesh ):
meshPart = meshPart.mesh
- fun = self._getFunctor( funType )
+ fun = self.GetFunctor( funType )
if fun:
if meshPart:
if hasattr( meshPart, "SetMesh" ):
</message>
<message>
<source>SMESH_DISTR_EXPR</source>
- <translation>Distribution with analitic density</translation>
+ <translation>Distribution with analytic density</translation>
</message>
<message>
<source>SMESH_DISTR_REGULAR</source>