diff --git a/doc/salome/examples/CMakeLists.txt b/doc/salome/examples/CMakeLists.txt
index d8c4631f8..aefec539d 100644
--- a/doc/salome/examples/CMakeLists.txt
+++ b/doc/salome/examples/CMakeLists.txt
@@ -63,6 +63,7 @@ SET(GOOD_TESTS
defining_hypotheses_ex14.py
defining_hypotheses_ex15.py
defining_hypotheses_ex16.py
+ defining_hypotheses_adaptive1d.py
filters_ex01.py
filters_ex03.py
filters_ex04.py
diff --git a/doc/salome/examples/defining_hypotheses_adaptive1d.py b/doc/salome/examples/defining_hypotheses_adaptive1d.py
new file mode 100644
index 000000000..f53434a85
--- /dev/null
+++ b/doc/salome/examples/defining_hypotheses_adaptive1d.py
@@ -0,0 +1,30 @@
+import salome, math
+salome.salome_init()
+from salome.geom import geomBuilder
+geompy = geomBuilder.New(salome.myStudy)
+from salome.smesh import smeshBuilder
+smesh = smeshBuilder.New(salome.myStudy)
+
+
+box = geompy.MakeBoxDXDYDZ( 100, 100, 100 )
+tool = geompy.MakeTranslation( box, 50, 0, 10 )
+axis = geompy.MakeVector( geompy.MakeVertex( 100, 0, 100 ),geompy.MakeVertex( 100, 10, 100 ),)
+tool = geompy.Rotate( tool, axis, math.pi * 25 / 180. )
+shape = geompy.MakeCut( box, tool )
+cyl = geompy.MakeCylinder( geompy.MakeVertex( -10,5, 95 ), geompy.MakeVectorDXDYDZ(1,0,0), 2, 90)
+shape = geompy.MakeCut( shape, cyl )
+tool = geompy.MakeBoxTwoPnt( geompy.MakeVertex( -10, 2, 15 ), geompy.MakeVertex( 90, 5, 16 ))
+shape = geompy.MakeCut( shape, tool, theName="shape" )
+
+# Parameters of Adaptive hypothesis. minSize and maxSize are such that they do not limit
+# size of segments because size of geometrical features lies within [2.-100.] range, hence
+# size of segments is defined by deflection parameter and size of geometrical features only.
+minSize = 0.1
+maxSize = 200
+deflection = 0.05
+
+mesh = smesh.Mesh( shape )
+mesh.Segment().Adaptive( minSize, maxSize, deflection )
+mesh.Triangle( smeshBuilder.NETGEN_2D )
+mesh.Compute()
+
diff --git a/doc/salome/gui/SMESH/images/adaptive1d.png b/doc/salome/gui/SMESH/images/adaptive1d.png
new file mode 100644
index 000000000..8091c8d0e
Binary files /dev/null and b/doc/salome/gui/SMESH/images/adaptive1d.png differ
diff --git a/doc/salome/gui/SMESH/images/adaptive1d_sample_mesh.png b/doc/salome/gui/SMESH/images/adaptive1d_sample_mesh.png
new file mode 100644
index 000000000..034207f2c
Binary files /dev/null and b/doc/salome/gui/SMESH/images/adaptive1d_sample_mesh.png differ
diff --git a/doc/salome/gui/SMESH/input/1d_meshing_hypo.doc b/doc/salome/gui/SMESH/input/1d_meshing_hypo.doc
index 367a0d0b5..5deb1344a 100644
--- a/doc/salome/gui/SMESH/input/1d_meshing_hypo.doc
+++ b/doc/salome/gui/SMESH/input/1d_meshing_hypo.doc
@@ -4,6 +4,7 @@
+\ref adaptive_1d_anchor "Adaptive"
\ref arithmetic_1d_anchor "Arithmetic 1D"
\ref average_length_anchor "Local Length"
\ref max_length_anchor "Max Size"
@@ -14,6 +15,28 @@
\ref fixed_points_1d_anchor "Fixed points 1D"
+
+\anchor adaptive_1d_anchor
+Adaptive hypothesis
+
+Adaptive hypothesis allows to split edges into segments with a
+length that depends on curvature of edges and faces and is limited
+from up and down. In addition length of a segment depends on lengths
+of adjacent segments (that can't differ more than twice) and on
+distance to close geometrical entities (edges and faces) to avoid
+creation of narrow 2D elements.
+
+\image html adaptive1d.png
+
+Min size parameter limits minimal segment size. Max size
+parameter defines length of segments on stright edges. \b Deflection
+parameter gives maximal distance of a segment from a curved edge.
+
+\image html adaptive1d_sample_mesh.png "A geometry and a mesh generated on this geometry using Adaptive hypothesis and Netgen 2D algorithm - the size of mesh segments reflects size of geometrical features"
+
+See Also a \ref tui_1d_adaptive "sample TUI Script" that
+creates the mesh of the above image.
+
\anchor arithmetic_1d_anchor
Arithmetic 1D hypothesis
@@ -26,7 +49,7 @@ The direction of the splitting is defined by the orientation of the underlying g
"Reverse Edges" list box allows to specify the edges for which the splitting should be made
in the direction opposing to their orientation. This list box is enabled only if the geometry object
is selected for the meshing. In this case the user can select edges to be reversed either directly
-picking them in the 3D viewer or by selecting the edges or groups of edges in the Object browser.
+picking them in the 3D viewer or by selecting the edges or groups of edges in the Object Browser.
\image html a-arithmetic1d.png
@@ -117,7 +140,7 @@ The direction of the splitting is defined by the orientation of the underlying g
"Reverse Edges" list box allows to specify the edges for which the splitting should be made
in the direction opposing to their orientation. This list box is enabled only if the geometry object
is selected for the meshing. In this case the user can select edges to be reversed either directly
-picking them in the 3D viewer or by selecting the edges or groups of edges in the Object browser.
+picking them in the 3D viewer or by selecting the edges or groups of edges in the Object Browser.
\image html image46.gif
@@ -166,7 +189,7 @@ The direction of the splitting is defined by the orientation of the underlying g
"Reverse Edges" list box allows to specify the edges for which the splitting should be made
in the direction opposing to their orientation. This list box is enabled only if the geometry object
is selected for the meshing. In this case the user can select edges to be reversed either directly
-picking them in the 3D viewer or by selecting the edges or groups of edges in the Object browser.
+picking them in the 3D viewer or by selecting the edges or groups of edges in the Object Browser.
\image html a-startendlength.png
@@ -215,7 +238,7 @@ direction opposite to their orientation. This list box is enabled only
if the geometrical object is selected for meshing. In this case it is
possible to select the edges to be reversed either directly picking them in
the 3D viewer or selecting the edges or groups of edges in the
-Object browser.
+Object Browser.
\image html mesh_fixedpnt.png "Example of a submesh on the edge built using Fixed points 1D hypothesis"
diff --git a/doc/salome/gui/SMESH/input/about_hypo.doc b/doc/salome/gui/SMESH/input/about_hypo.doc
index e4bf36ca0..09768cc7c 100644
--- a/doc/salome/gui/SMESH/input/about_hypo.doc
+++ b/doc/salome/gui/SMESH/input/about_hypo.doc
@@ -3,8 +3,8 @@
\page about_hypo_page About Hypotheses
\b Hypotheses represent boundary conditions which will be taken into
-account at calculations of meshes or sub-meshes basing on geometrical
-objects. These hypotheses allow you to manage the level of detail of
+account at calculations of meshes or sub-meshes.
+These hypotheses allow you to manage the level of detail of
the resulting meshes or sub-meshes: when applying different hypotheses
with different parameters you can preset the quantity or size of
elements which will compose your mesh. So, it will be possible to
@@ -15,12 +15,13 @@ In \b MESH there are the following Basic Hypotheses:
\subpage a1d_meshing_hypo_page "1D Hypotheses" (for meshing of
edges ):
-\ref arithmetic_1d_anchor "Arithmetic 1D"
+\ref number_of_segments_anchor "Number of segments"
\ref average_length_anchor "Local Length"
\ref max_length_anchor "Max Size"
-\ref deflection_1d_anchor "Deflection 1D"
-\ref number_of_segments_anchor "Number of segments"
+\ref adaptive_1d_anchor "Adaptive"
+\ref arithmetic_1d_anchor "Arithmetic 1D"
\ref start_and_end_length_anchor "Start and end length"
+\ref deflection_1d_anchor "Deflection 1D"
\ref automatic_length_anchor "Automatic Length"
\subpage a2d_meshing_hypo_page "2D Hypotheses" (for meshing of faces ):
diff --git a/doc/salome/gui/SMESH/input/tui_defining_hypotheses.doc b/doc/salome/gui/SMESH/input/tui_defining_hypotheses.doc
index 71abf33b6..333017d77 100644
--- a/doc/salome/gui/SMESH/input/tui_defining_hypotheses.doc
+++ b/doc/salome/gui/SMESH/input/tui_defining_hypotheses.doc
@@ -7,6 +7,7 @@ This page provides example codes of \ref tui_defining_meshing_algos
Wire discretisation 1D algorithm
+ \ref tui_1d_adaptive "Adaptive 1D" hypothesis
\ref tui_1d_arithmetic "Arithmetic 1D" hypothesis
\ref tui_deflection_1d "Deflection 1D and Number of Segments" hypotheses
\ref tui_start_and_end_length "Start and End Length" hypotheses
@@ -46,6 +47,11 @@ This page provides example codes of \ref tui_defining_meshing_algos
Arithmetic 1D
\tui_script{defining_hypotheses_ex01.py}
+
+\anchor tui_1d_adaptive
+Adaptive
+\tui_script{defining_hypotheses_adaptive1d.py}
+
\anchor tui_deflection_1d
Deflection 1D and Number of Segments
diff --git a/idl/SMESH_BasicHypothesis.idl b/idl/SMESH_BasicHypothesis.idl
index b2bca113c..798475b30 100644
--- a/idl/SMESH_BasicHypothesis.idl
+++ b/idl/SMESH_BasicHypothesis.idl
@@ -385,7 +385,6 @@ module StdMeshers
double GetDeflection();
};
-
/*!
* StdMeshers_FixedPoints1D: interface of "Fixed points 1D" hypothesis
*/
@@ -433,6 +432,30 @@ module StdMeshers
string GetObjectEntry();
};
+ /*!
+ * StdMeshers_Adaptive1D: interface of "Adaptive" hypothesis
+ */
+ interface StdMeshers_Adaptive1D : SMESH::SMESH_Hypothesis
+ {
+ /*!
+ * Sets minimal allowed segment length
+ */
+ void SetMinSize(in double minSegLen) raises (SALOME::SALOME_Exception);
+ double GetMinSize();
+
+ /*!
+ * Sets maximal allowed segment length
+ */
+ void SetMaxSize(in double maxSegLen) raises (SALOME::SALOME_Exception);
+ double GetMaxSize();
+
+ /*!
+ * Sets parameter value,
+ * i.e. a maximal allowed distance between a segment and an edge.
+ */
+ void SetDeflection(in double deflection) raises (SALOME::SALOME_Exception);
+ double GetDeflection();
+ };
/*!
* StdMeshers_MaxElementVolume: interface of "Max. Hexahedron or Tetrahedron Volume" hypothesis
diff --git a/resources/StdMeshers.xml.in b/resources/StdMeshers.xml.in
index c205f0355..d80b4e7d9 100644
--- a/resources/StdMeshers.xml.in
+++ b/resources/StdMeshers.xml.in
@@ -75,6 +75,11 @@
icon-id ="mesh_hypo_length.png"
dim ="1"/>
+
+
Arithmetic1D=Arithmetic1D(SetStartLength(),SetEndLength(),SetReversedEdges())
StartEndLength=StartEndLength(SetStartLength(),SetEndLength(),SetReversedEdges())
Deflection1D=Deflection1D(SetDeflection())
+ Adaptive1D=Adaptive(SetMinSize(),SetMaxSize(),SetDeflection())
AutomaticLength=AutomaticLength(SetFineness())
FixedPoints1D=FixedPoints1D(SetPoints(),SetNbSegments(),SetReversedEdges())
Propagation=Propagation()
@@ -222,7 +228,7 @@
Arithmetic1D=Arithmetic1D(SetStartLength(),SetEndLength(),SetReversedEdges())
StartEndLength=StartEndLength(SetStartLength(),SetEndLength(),SetReversedEdges())
Deflection1D=Deflection1D(SetDeflection())
+ Adaptive1D=Adaptive(SetMinSize(),SetMaxSize(),SetDeflection())
AutomaticLength=AutomaticLength(SetFineness())
FixedPoints1D=FixedPoints1D(SetPoints(),SetNbSegments(),SetReversedEdges())
Propagation=Propagation()
diff --git a/src/SMESH/SMESH_Mesh.cxx b/src/SMESH/SMESH_Mesh.cxx
index 6f1edc645..4c1383356 100644
--- a/src/SMESH/SMESH_Mesh.cxx
+++ b/src/SMESH/SMESH_Mesh.cxx
@@ -876,7 +876,7 @@ SMESH_Hypothesis * SMESH_Mesh::GetHypothesis(const int anHypId) const
{
StudyContextStruct *sc = _gen->GetStudyContext(_studyId);
if (sc->mapHypothesis.find(anHypId) == sc->mapHypothesis.end())
- return false;
+ return NULL;
SMESH_Hypothesis *anHyp = sc->mapHypothesis[anHypId];
return anHyp;
diff --git a/src/SMESHGUI/SMESHGUI_Hypotheses.cxx b/src/SMESHGUI/SMESHGUI_Hypotheses.cxx
index 77d8ec1b2..fa9add8e0 100644
--- a/src/SMESHGUI/SMESHGUI_Hypotheses.cxx
+++ b/src/SMESHGUI/SMESHGUI_Hypotheses.cxx
@@ -561,6 +561,8 @@ QString SMESHGUI_GenericHypothesisCreator::helpPage() const
aHelpFileName = "a1d_meshing_hypo_page.html#start_and_end_length_anchor";
else if ( aHypType == "Deflection1D")
aHelpFileName = "a1d_meshing_hypo_page.html#deflection_1d_anchor";
+ else if ( aHypType == "Adaptive1D")
+ aHelpFileName = "a1d_meshing_hypo_page.html#adaptive_1d_anchor";
else if ( aHypType == "AutomaticLength")
aHelpFileName = "a1d_meshing_hypo_page.html#automatic_length_anchor";
else if ( aHypType == "NumberOfSegments")
diff --git a/src/SMESH_I/SMESH_Gen_i.hxx b/src/SMESH_I/SMESH_Gen_i.hxx
index 4e2b9b754..6b134e51f 100644
--- a/src/SMESH_I/SMESH_Gen_i.hxx
+++ b/src/SMESH_I/SMESH_Gen_i.hxx
@@ -486,8 +486,8 @@ public:
// SIMAN-related functions (check out/check in) : import data to study
virtual Engines::ListOfIdentifiers* importData(CORBA::Long studyId,
- Engines::DataContainer_ptr data,
- const Engines::ListOfOptions& options);
+ Engines::DataContainer_ptr data,
+ const Engines::ListOfOptions& options);
// SIMAN-related functions (check out/check in) : get modified data
virtual Engines::ListOfData* getModifiedData(CORBA::Long studyId);
diff --git a/src/SMESH_SWIG/StdMeshersBuilder.py b/src/SMESH_SWIG/StdMeshersBuilder.py
index ee05f82ef..32d2724f9 100644
--- a/src/SMESH_SWIG/StdMeshersBuilder.py
+++ b/src/SMESH_SWIG/StdMeshersBuilder.py
@@ -178,6 +178,28 @@ class StdMeshersBuilder_Segment(Mesh_Algorithm):
return True
return False
+ ## Defines "Adaptive" hypothesis to cut an edge into segments keeping segment size
+ # within the given range and considering (1) deflection of segments from the edge
+ # and (2) distance from segments to closest edges and faces to have segment length
+ # not longer than two times shortest distances to edges and faces.
+ # @param minSize defines the minimal allowed segment length
+ # @param maxSize defines the maximal allowed segment length
+ # @param deflection defines the maximal allowed distance from a segment to an edge
+ # @param UseExisting if ==true - searches for an existing hypothesis created with
+ # the same parameters, else (default) - creates a new one
+ # @return an instance of StdMeshers_Adaptive1D hypothesis
+ # @ingroup l3_hypos_1dhyps
+ def Adaptive(self, minSize, maxSize, deflection, UseExisting=False):
+ compFun = lambda hyp, args: ( IsEqual(hyp.GetMinSize(), args[0]) and \
+ IsEqual(hyp.GetMaxSize(), args[1]) and \
+ IsEqual(hyp.GetDeflection(), args[2]))
+ hyp = self.Hypothesis("Adaptive1D", [minSize, maxSize, deflection],
+ UseExisting=UseExisting, CompareMethod=compFun)
+ hyp.SetMinSize(minSize)
+ hyp.SetMaxSize(maxSize)
+ hyp.SetDeflection(deflection)
+ return hyp
+
## Defines "Arithmetic1D" hypothesis to cut an edge in several segments with increasing arithmetic length
# @param start defines the length of the first segment
# @param end defines the length of the last segment
diff --git a/src/StdMeshers/CMakeLists.txt b/src/StdMeshers/CMakeLists.txt
index 040bb90f0..de84b5026 100644
--- a/src/StdMeshers/CMakeLists.txt
+++ b/src/StdMeshers/CMakeLists.txt
@@ -186,6 +186,7 @@ SET(StdMeshers_SOURCES
StdMeshers_Projection_1D2D.cxx
StdMeshers_CartesianParameters3D.cxx
StdMeshers_Cartesian_3D.cxx
+ StdMeshers_Adaptive1D.cxx
)
IF(SALOME_SMESH_ENABLE_MEFISTO)
diff --git a/src/StdMeshers/StdMeshers_Adaptive1D.cxx b/src/StdMeshers/StdMeshers_Adaptive1D.cxx
new file mode 100644
index 000000000..5078dd42a
--- /dev/null
+++ b/src/StdMeshers/StdMeshers_Adaptive1D.cxx
@@ -0,0 +1,1194 @@
+// Copyright (C) 2007-2013 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.
+//
+// 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 : StdMeshers_Adaptive1D.cxx
+// Module : SMESH
+//
+#include "StdMeshers_Adaptive1D.hxx"
+
+#include "SMESH_Gen.hxx"
+#include "SMESH_Mesh.hxx"
+#include "SMESH_MesherHelper.hxx"
+#include "SMESH_Octree.hxx"
+#include "SMESH_subMesh.hxx"
+#include "SMESH_HypoFilter.hxx"
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+using namespace std;
+
+namespace // internal utils
+{
+ //================================================================================
+ /*!
+ * \brief Working data of an EDGE
+ */
+ struct EdgeData
+ {
+ struct ProbePnt
+ {
+ gp_Pnt myP;
+ double myU;
+ double mySegSize;
+ ProbePnt( gp_Pnt p, double u, double sz=1e100 ): myP( p ), myU( u ), mySegSize( sz ) {}
+ };
+ BRepAdaptor_Curve myC3d;
+ double myLength;
+ list< ProbePnt > myPoints;
+
+ typedef list< ProbePnt >::iterator TPntIter;
+ void AddPoint( TPntIter where, double u )
+ {
+ myPoints.insert( where, ProbePnt( myC3d.Value( u ), u ));
+ }
+ const ProbePnt& First() const { return myPoints.front(); }
+ const ProbePnt& Last() const { return myPoints.back(); }
+ const TopoDS_Edge& Edge() const { return myC3d.Edge(); }
+ };
+
+ //================================================================================
+ /*!
+ * \brief Bnd_B3d with access to its center and half-size
+ */
+ struct BBox : public Bnd_B3d
+ {
+ gp_XYZ Center() const { return gp_XYZ( myCenter[0], myCenter[1], myCenter[2] ); }
+ gp_XYZ HSize() const { return gp_XYZ( myHSize[0], myHSize[1], myHSize[2] ); }
+ double Size() const { return 2 * myHSize[0]; }
+ };
+ //================================================================================
+ /*!
+ * \brief Octree of local segment size
+ */
+ class SegSizeTree : public SMESH_Octree
+ {
+ double mySegSize; // segment size
+
+ // structure holding some common parameters of SegSizeTree
+ struct _CommonData : public SMESH_TreeLimit
+ {
+ double myGrading, myMinSize, myMaxSize;
+ };
+ _CommonData* getData() const { return (_CommonData*) myLimit; }
+
+ SegSizeTree(double size): SMESH_Octree(), mySegSize(size)
+ {
+ allocateChildren();
+ }
+ void allocateChildren()
+ {
+ myChildren = new SMESH_Octree::TBaseTree*[nbChildren()];
+ for ( int i = 0; i < nbChildren(); ++i )
+ myChildren[i] = NULL;
+ }
+ virtual box_type* buildRootBox() { return 0; }
+ virtual SegSizeTree* newChild() const { return 0; }
+ virtual void buildChildrenData() {}
+
+ public:
+
+ SegSizeTree( Bnd_B3d & bb, double grading, double mixSize, double maxSize);
+ void SetSize( const gp_Pnt& p, double size );
+ double SetSize( const gp_Pnt& p1, const gp_Pnt& p2 );
+ double GetSize( const gp_Pnt& p ) const;
+ const BBox* GetBox() const { return (BBox*) getBox(); }
+ double GetMinSize() { return getData()->myMinSize; }
+ };
+ //================================================================================
+ /*!
+ * \brief Data of triangle used to locate it in an octree and to find distance
+ * to a point
+ */
+ struct Triangle
+ {
+ Bnd_B3d myBox;
+ // data for DistToProjection()
+ gp_XYZ myN0, myEdge1, myEdge2, myNorm, myPVec;
+ double myInvDet, myMaxSize2;
+
+ void Init( const gp_Pnt& n1, const gp_Pnt& n2, const gp_Pnt& n3 );
+ bool DistToProjection( const gp_Pnt& p, double& dist ) const;
+ };
+ //================================================================================
+ /*!
+ * \brief Element data held by ElementBndBoxTree + algorithm computing a distance
+ * from a point to element
+ */
+ class ElementBndBoxTree;
+ struct ElemTreeData : public SMESH_TreeLimit
+ {
+ virtual const Bnd_B3d* GetBox(int elemID) const = 0;
+ };
+ struct TriaTreeData : public ElemTreeData
+ {
+ vector< Triangle > myTrias;
+ double myFaceTol;
+ double myTriasDeflection;
+ const ElementBndBoxTree* myTree;
+ const Poly_Array1OfTriangle* myPolyTrias;
+ const TColgp_Array1OfPnt* myNodes;
+ bool myOwnNodes;
+
+ TriaTreeData( const TopoDS_Face& face, ElementBndBoxTree* triaTree );
+ ~TriaTreeData() { if ( myOwnNodes ) delete myNodes; myNodes = NULL; }
+ virtual const Bnd_B3d* GetBox(int elemID) const { return &myTrias[elemID].myBox; }
+ void SetSizeByTrias( SegSizeTree& sizeTree, double deflection ) const;
+ double GetMinDistInSphere(const gp_Pnt& p,
+ const double radius,
+ const bool projectedOnly,
+ const gp_Pnt* avoidP=0) const;
+ };
+ //================================================================================
+ /*!
+ * \brief Octree of triangles or segments
+ */
+ class ElementBndBoxTree : public SMESH_Octree
+ {
+ public:
+ ElementBndBoxTree(const TopoDS_Face& face);
+ void GetElementsInSphere( const gp_XYZ& center,
+ const double radius, std::set & foundElemIDs) const;
+ ElemTreeData* GetElemData() const { return (ElemTreeData*) myLimit; }
+ TriaTreeData* GetTriaData() const { return (TriaTreeData*) myLimit; }
+
+ protected:
+ ElementBndBoxTree() {}
+ SMESH_Octree* newChild() const { return new ElementBndBoxTree; }
+ void buildChildrenData();
+ Bnd_B3d* buildRootBox();
+ private:
+ vector< int > _elementIDs;
+ };
+ //================================================================================
+ /*!
+ * \brief BRepMesh_IncrementalMesh with access to its protected Bnd_Box
+ */
+ struct IncrementalMesh : public BRepMesh_IncrementalMesh
+ {
+ IncrementalMesh(const TopoDS_Shape& shape,
+ const Standard_Real deflection,
+ const bool relative):
+ BRepMesh_IncrementalMesh( shape, deflection, relative )
+ {
+ }
+ Bnd_B3d GetBox() const
+ {
+ Standard_Real TXmin, TYmin, TZmin, TXmax, TYmax, TZmax;
+ myBox.Get(TXmin, TYmin, TZmin, TXmax, TYmax, TZmax);
+ Bnd_B3d bb;
+ bb.Add( gp_XYZ( TXmin, TYmin, TZmin ));
+ bb.Add( gp_XYZ( TXmax, TYmax, TZmax ));
+ return bb;
+ }
+ };
+
+ //================================================================================
+ /*!
+ * \brief Initialize TriaTreeData
+ */
+ //================================================================================
+
+ TriaTreeData::TriaTreeData( const TopoDS_Face& face, ElementBndBoxTree* triaTree )
+ : myTree(NULL), myPolyTrias(NULL), myNodes(NULL), myOwnNodes(false), myTriasDeflection(0)
+ {
+ TopLoc_Location loc;
+ Handle(Poly_Triangulation) tr = BRep_Tool::Triangulation( face, loc );
+ if ( !tr.IsNull() )
+ {
+ myFaceTol = SMESH_MesherHelper::MaxTolerance( face );
+ myTree = triaTree;
+ myNodes = & tr->Nodes();
+ myPolyTrias = & tr->Triangles();
+ myTriasDeflection = tr->Deflection();
+ if ( !loc.IsIdentity() ) // transform nodes if necessary
+ {
+ TColgp_Array1OfPnt* trsfNodes = new TColgp_Array1OfPnt( myNodes->Lower(), myNodes->Upper() );
+ trsfNodes->Assign( *myNodes );
+ myNodes = trsfNodes;
+ myOwnNodes = true;
+ const gp_Trsf& trsf = loc;
+ for ( int i = trsfNodes->Lower(); i <= trsfNodes->Upper(); ++i )
+ trsfNodes->ChangeValue(i).Transform( trsf );
+ }
+ myTrias.resize( myPolyTrias->Length() );
+ Standard_Integer n1,n2,n3;
+ for ( int i = 1; i <= myPolyTrias->Upper(); ++i )
+ {
+ myPolyTrias->Value( i ).Get( n1,n2,n3 );
+ myTrias[ i-1 ].Init( myNodes->Value( n1 ),
+ myNodes->Value( n2 ),
+ myNodes->Value( n3 ));
+ }
+ // TODO: mark triangles with nodes on VERTEXes to
+ // less frequently compare with avoidPnt in GetMinDistInSphere()
+ //
+ // Handle(Poly_PolygonOnTriangulation) polygon =
+ // BRep_Tool::PolygonOnTriangulation( edge, tr, loc );
+ // if ( polygon.IsNull() /*|| !pologon.HasParameters()*/ )
+ // continue;
+ // Handle(TColStd_Array1OfInteger) nodeIDs = polygon->Nodes();
+ }
+ }
+ //================================================================================
+ /*!
+ * \brief Set size of segments by size of triangles
+ */
+ //================================================================================
+
+ void TriaTreeData::SetSizeByTrias( SegSizeTree& sizeTree, double deflection ) const
+ {
+ if ( myTriasDeflection <= std::numeric_limits::min() )
+ return;
+ const double factor = deflection / myTriasDeflection;
+
+ Standard_Integer n1,n2,n3;
+ gp_Pnt p[4];
+ double a[3];
+ for ( int i = 1; i <= myPolyTrias->Upper(); ++i )
+ {
+ // compute minimal altitude of a triangle
+ myPolyTrias->Value( i ).Get( n1,n2,n3 );
+ p[0] = myNodes->Value( n1 );
+ p[1] = myNodes->Value( n2 );
+ p[2] = myNodes->Value( n3 );
+ p[3] = p[0];
+ a[0] = p[0].Distance( p[1] );
+ a[1] = p[1].Distance( p[2] );
+ a[2] = p[2].Distance( p[3] );
+ double maxSide = Max( a[0], Max( a[1], a[2] ));
+ double s = 0.5 * ( a[0] + a[1] + a[2] );
+ double area = sqrt( s * (s - a[0]) * (s - a[1]) * (s - a[2]));
+ double sz = 2 * area / maxSide; // minimal altitude
+ for ( int j = 0; j < 3; ++j )
+ {
+ int nb = 2 * int( a[j] / sz + 0.5 );
+ for ( int k = 1; k <= nb; ++k )
+ {
+ double r = double( k ) / nb;
+ sizeTree.SetSize( r * p[j].XYZ() + ( 1-r ) * p[j+1].XYZ(), sz * factor );
+ }
+ }
+ sizeTree.SetSize(( p[0].XYZ() + p[1].XYZ() + p[2].XYZ()) / 3., sz * factor );
+ //cout << "SetSizeByTrias, i="<< i << " " << sz * factor << endl;
+ }
+ }
+ //================================================================================
+ /*!
+ * \brief Return minimal distance from a given point to a trinangle but not more
+ * distant than a given radius. Triangles with a node at avoidPnt are ignored.
+ * If projectedOnly,
+ */
+ //================================================================================
+
+ double TriaTreeData::GetMinDistInSphere(const gp_Pnt& p,
+ const double radius,
+ const bool projectedOnly,
+ const gp_Pnt* avoidPnt) const
+ {
+ double minDist2 = 1e100;
+ const double tol2 = myFaceTol * myFaceTol;
+
+ std::set foundElemIDs;
+ myTree->GetElementsInSphere( p.XYZ(), radius, foundElemIDs );
+
+ std::set::iterator id = foundElemIDs.begin();
+ Standard_Integer n[ 3 ];
+ for ( ; id != foundElemIDs.end(); ++id )
+ {
+ double d, minD2 = minDist2;
+ bool avoidTria = false;
+ myPolyTrias->Value( *id+1 ).Get( n[0],n[1],n[2] );
+ for ( int i = 0; i < 3; ++i )
+ {
+ const gp_Pnt& pn = myNodes->Value(n[i]);
+ if ( avoidTria = ( avoidPnt && pn.SquareDistance(*avoidPnt) <= tol2 ))
+ break;
+ if ( !projectedOnly )
+ minD2 = Min( minD2, pn.SquareDistance( p ));
+ }
+ if ( !avoidTria )
+ {
+ const Triangle& t = myTrias[ *id ];
+ if ( minD2 < t.myMaxSize2 && t.DistToProjection( p, d ))
+ minD2 = Min( minD2, d*d );
+ minDist2 = Min( minDist2, minD2 );
+ }
+ }
+ return sqrt( minDist2 );
+ }
+ //================================================================================
+ /*!
+ * \brief Prepare Triangle data
+ */
+ //================================================================================
+
+ void Triangle::Init( const gp_Pnt& p1, const gp_Pnt& p2, const gp_Pnt& p3 )
+ {
+ myBox.Add( p1 );
+ myBox.Add( p2 );
+ myBox.Add( p3 );
+ myN0 = p1.XYZ();
+ myEdge1 = p2.XYZ() - myN0;
+ myEdge2 = p3.XYZ() - myN0;
+ myNorm = myEdge1 ^ myEdge2;
+ double normSize = myNorm.Modulus();
+ if ( normSize > std::numeric_limits::min() )
+ {
+ myNorm /= normSize;
+ myPVec = myNorm ^ myEdge2;
+ myInvDet = 1. / ( myEdge1 * myPVec );
+ }
+ else
+ {
+ myInvDet = 0.;
+ }
+ myMaxSize2 = Max( p2.SquareDistance( p3 ),
+ Max( myEdge2.SquareModulus(), myEdge1.SquareModulus() ));
+ }
+ //================================================================================
+ /*!
+ * \brief Compute distance from a point to the triangle. Return false if the point
+ * is not projected inside the triangle
+ */
+ //================================================================================
+
+ bool Triangle::DistToProjection( const gp_Pnt& p, double& dist ) const
+ {
+ if ( myInvDet == 0 )
+ return false; // degenerated triangle
+
+ /* distance from n0 to the point */
+ gp_XYZ tvec = p.XYZ() - myN0;
+
+ /* calculate U parameter and test bounds */
+ double u = ( tvec * myPVec ) * myInvDet;
+ if (u < 0.0 || u > 1.0)
+ return false; // projected outside the triangle
+
+ /* calculate V parameter and test bounds */
+ gp_XYZ qvec = tvec ^ myEdge1;
+ double v = ( myNorm * qvec) * myInvDet;
+ if ( v < 0.0 || u + v > 1.0 )
+ return false; // projected outside the triangle
+
+ dist = ( myEdge2 * qvec ) * myInvDet;
+ return true;
+ }
+
+ //================================================================================
+ /*!
+ * \brief Consturct ElementBndBoxTree of Poly_Triangulation of a FACE
+ */
+ //================================================================================
+
+ ElementBndBoxTree::ElementBndBoxTree(const TopoDS_Face& face)
+ :SMESH_Octree()
+ {
+ TriaTreeData* data = new TriaTreeData( face, this );
+ data->myMaxLevel = 5;
+ myLimit = data;
+
+ if ( !data->myTrias.empty() )
+ {
+ for ( size_t i = 0; i < data->myTrias.size(); ++i )
+ _elementIDs.push_back( i );
+
+ compute();
+ }
+ }
+ //================================================================================
+ /*!
+ * \brief Return the maximal box
+ */
+ //================================================================================
+
+ Bnd_B3d* ElementBndBoxTree::buildRootBox()
+ {
+ Bnd_B3d* box = new Bnd_B3d;
+ ElemTreeData* data = GetElemData();
+ for ( int i = 0; i < _elementIDs.size(); ++i )
+ box->Add( *data->GetBox( _elementIDs[i] ));
+ return box;
+ }
+
+ //================================================================================
+ /*!
+ * \brief Redistrubute element boxes among children
+ */
+ //================================================================================
+
+ void ElementBndBoxTree::buildChildrenData()
+ {
+ ElemTreeData* data = GetElemData();
+ for ( int i = 0; i < _elementIDs.size(); ++i )
+ {
+ const Bnd_B3d* elemBox = data->GetBox( _elementIDs[i] );
+ for (int j = 0; j < 8; j++)
+ if ( !elemBox->IsOut( *myChildren[j]->getBox() ))
+ ((ElementBndBoxTree*)myChildren[j])->_elementIDs.push_back( _elementIDs[i] );
+ }
+ SMESHUtils::FreeVector( _elementIDs ); // = _elements.clear() + free memory
+
+ const int theMaxNbElemsInLeaf = 7;
+
+ for (int j = 0; j < 8; j++)
+ {
+ ElementBndBoxTree* child = static_cast( myChildren[j] );
+ if ( child->_elementIDs.size() <= theMaxNbElemsInLeaf )
+ child->myIsLeaf = true;
+ }
+ }
+ //================================================================================
+ /*!
+ * \brief Return elements from leaves intersecting the sphere
+ */
+ //================================================================================
+
+ void ElementBndBoxTree::GetElementsInSphere( const gp_XYZ& center,
+ const double radius,
+ std::set & foundElemIDs) const
+ {
+ if ( const box_type* box = getBox() )
+ {
+ if ( box->IsOut( center, radius ))
+ return;
+
+ if ( isLeaf() )
+ {
+ ElemTreeData* data = GetElemData();
+ for ( int i = 0; i < _elementIDs.size(); ++i )
+ if ( !data->GetBox( _elementIDs[i] )->IsOut( center, radius ))
+ foundElemIDs.insert( _elementIDs[i] );
+ }
+ else
+ {
+ for (int i = 0; i < 8; i++)
+ ((ElementBndBoxTree*) myChildren[i])->GetElementsInSphere( center, radius, foundElemIDs );
+ }
+ }
+ }
+
+ //================================================================================
+ /*!
+ * \brief Constructor of SegSizeTree
+ * \param [in,out] bb - bounding box enclosing all EDGEs to discretize
+ * \param [in] grading - factor to get max size of the neighbour segment by
+ * size of a current one.
+ */
+ //================================================================================
+
+ SegSizeTree::SegSizeTree( Bnd_B3d & bb, double grading, double minSize, double maxSize )
+ : SMESH_Octree( new _CommonData() )
+ {
+ // make cube myBox from the box bb
+ gp_XYZ pmin = bb.CornerMin(), pmax = bb.CornerMax();
+ double maxBoxHSize = 0.5 * Max( pmax.X()-pmin.X(), Max( pmax.Y()-pmin.Y(), pmax.Z()-pmin.Z() ));
+ maxBoxHSize *= 1.01;
+ bb.SetHSize( gp_XYZ( maxBoxHSize, maxBoxHSize, maxBoxHSize ));
+ myBox = new box_type( bb );
+
+ mySegSize = Min( 2 * maxBoxHSize, maxSize );
+
+ getData()->myGrading = grading;
+ getData()->myMinSize = Max( minSize, 2*maxBoxHSize / 1.e6 );
+ getData()->myMaxSize = maxSize;
+ allocateChildren();
+ }
+
+ //================================================================================
+ /*!
+ * \brief Set segment size at a given point
+ */
+ //================================================================================
+
+ void SegSizeTree::SetSize( const gp_Pnt& p, double size )
+ {
+ // check if the point is out of the largest cube
+ SegSizeTree* root = this;
+ while ( root->myFather )
+ root = (SegSizeTree*) root->myFather;
+ if ( root->getBox()->IsOut( p.XYZ() ))
+ return;
+
+ // keep size whthin the valid range
+ size = Max( size, getData()->myMinSize );
+ //size = Min( size, getData()->myMaxSize );
+
+ // find an existing leaf at the point
+ SegSizeTree* leaf = (SegSizeTree*) root;
+ int iChild;
+ while ( true )
+ {
+ iChild = SMESH_Octree::getChildIndex( p.X(), p.Y(), p.Z(), leaf->GetBox()->Center() );
+ if ( leaf->myChildren[ iChild ] )
+ leaf = (SegSizeTree*) leaf->myChildren[ iChild ];
+ else
+ break;
+ }
+ // don't increase the current size
+ if ( leaf->mySegSize <= 1.1 * size )
+ return;
+
+ // split the found leaf until its box size is less than the given size
+ const double rootSize = root->GetBox()->Size();
+ while ( leaf->GetBox()->Size() > size )
+ {
+ const BBox* bb = leaf->GetBox();
+ iChild = SMESH_Octree::getChildIndex( p.X(), p.Y(), p.Z(), bb->Center() );
+ SegSizeTree* newLeaf = new SegSizeTree( bb->Size() / 2 );
+ leaf->myChildren[iChild] = newLeaf;
+ newLeaf->myFather = leaf;
+ newLeaf->myLimit = leaf->myLimit;
+ newLeaf->myLevel = leaf->myLevel + 1;
+ newLeaf->myBox = leaf->newChildBox( iChild );
+ newLeaf->myBox->Enlarge( rootSize * 1e-10 );
+ //newLeaf->myIsLeaf = ( newLeaf->mySegSize <= size );
+ leaf = newLeaf;
+ }
+ leaf->mySegSize = size;
+
+ // propagate increased size out from the leaf
+ double boxSize = leaf->GetBox()->Size();
+ double sizeInc = size + boxSize * getData()->myGrading;
+ for ( int iDir = 1; iDir <= 3; ++iDir )
+ {
+ gp_Pnt outPnt = p;
+ outPnt.SetCoord( iDir, p.Coord( iDir ) + boxSize );
+ SetSize( outPnt, sizeInc );
+ outPnt.SetCoord( iDir, p.Coord( iDir ) - boxSize );
+ SetSize( outPnt, sizeInc );
+ }
+ }
+ //================================================================================
+ /*!
+ * \brief Set size of a segment given by two end points
+ */
+ //================================================================================
+
+ double SegSizeTree::SetSize( const gp_Pnt& p1, const gp_Pnt& p2 )
+ {
+ const double size = p1.Distance( p2 );
+ gp_XYZ p = 0.5 * ( p1.XYZ() + p2.XYZ() );
+ SetSize( p, size );
+ SetSize( p1, size );
+ SetSize( p2, size );
+ //cout << "SetSize " << p1.Distance( p2 ) << " at " << p.X() <<", "<< p.Y()<<", "<GetBox()->Center() );
+ if ( leaf->myChildren[ iChild ] )
+ leaf = (SegSizeTree*) leaf->myChildren[ iChild ];
+ else
+ return leaf->mySegSize;
+ }
+ return mySegSize; // just to return anything
+ }
+
+ //================================================================================
+ /*!
+ * \brief Evaluate curve deflection between two points
+ * \param theCurve - the curve
+ * \param theU1 - the parameter of the first point
+ * \param theU2 - the parameter of the second point
+ * \retval double - square deflection value
+ */
+ //================================================================================
+
+ double deflection2(const BRepAdaptor_Curve & theCurve,
+ double theU1,
+ double theU2)
+ {
+ // line between theU1 and theU2
+ gp_Pnt p1 = theCurve.Value( theU1 ), p2 = theCurve.Value( theU2 );
+ gp_Lin segment( p1, gp_Vec( p1, p2 ));
+
+ // evaluate square distance of theCurve from the segment
+ Standard_Real dist2 = 0;
+ const int nbPnt = 5;
+ const double step = ( theU2 - theU1 ) / nbPnt;
+ while (( theU1 += step ) < theU2 )
+ dist2 = Max( dist2, segment.SquareDistance( theCurve.Value( theU1 )));
+
+ return dist2;
+ }
+
+} // namespace
+
+//=======================================================================
+//function : StdMeshers_Adaptive1D
+//purpose : Constructor
+StdMeshers_Adaptive1D::StdMeshers_Adaptive1D(int hypId,
+ int studyId,
+ SMESH_Gen * gen)
+ :SMESH_Hypothesis(hypId, studyId, gen)
+{
+ myMinSize = 1e-10;
+ myMaxSize = 1e+10;
+ myDeflection = 1e-2;
+ myAlgo = NULL;
+ _name = "Adaptive1D";
+ _param_algo_dim = 1; // is used by SMESH_Regular_1D
+}
+//=======================================================================
+//function : ~StdMeshers_Adaptive1D
+//purpose : Destructor
+StdMeshers_Adaptive1D::~StdMeshers_Adaptive1D()
+{
+ delete myAlgo; myAlgo = NULL;
+}
+//=======================================================================
+//function : SetDeflection
+//purpose :
+void StdMeshers_Adaptive1D::SetDeflection(double value)
+ throw(SALOME_Exception)
+{
+ if (value <= std::numeric_limits::min() )
+ throw SALOME_Exception("Deflection must be greater that zero");
+ if (myDeflection != value)
+ {
+ myDeflection = value;
+ NotifySubMeshesHypothesisModification();
+ }
+}
+//=======================================================================
+//function : SetMinSize
+//purpose : Sets minimal allowed segment length
+void StdMeshers_Adaptive1D::SetMinSize(double minSize)
+ throw(SALOME_Exception)
+{
+ if (minSize <= std::numeric_limits::min() )
+ throw SALOME_Exception("Min size must be greater that zero");
+
+ if (myMinSize != minSize )
+ {
+ myMinSize = minSize;
+ NotifySubMeshesHypothesisModification();
+ }
+}
+//=======================================================================
+//function : SetMaxSize
+//purpose : Sets maximal allowed segment length
+void StdMeshers_Adaptive1D::SetMaxSize(double maxSize)
+ throw(SALOME_Exception)
+{
+ if (maxSize <= std::numeric_limits::min() )
+ throw SALOME_Exception("Max size must be greater that zero");
+
+ if (myMaxSize != maxSize )
+ {
+ myMaxSize = maxSize;
+ NotifySubMeshesHypothesisModification();
+ }
+}
+//=======================================================================
+//function : SaveTo
+//purpose : Persistence
+ostream & StdMeshers_Adaptive1D::SaveTo(ostream & save)
+{
+ save << myMinSize << " " << myMaxSize << " " << myDeflection;
+ save << " " << -1 << " " << -1; // preview addition of parameters
+ return save;
+}
+//=======================================================================
+//function : LoadFrom
+//purpose : Persistence
+istream & StdMeshers_Adaptive1D::LoadFrom(istream & load)
+{
+ int dummyParam;
+ bool isOK = (load >> myMinSize >> myMaxSize >> myDeflection >> dummyParam >> dummyParam);
+ if (!isOK)
+ load.clear(ios::badbit | load.rdstate());
+ return load;
+}
+//=======================================================================
+//function : SetParametersByMesh
+//purpose : Initialize parameters by the mesh built on the geometry
+//param theMesh - the built mesh
+//param theShape - the geometry of interest
+//retval bool - true if parameter values have been successfully defined
+bool StdMeshers_Adaptive1D::SetParametersByMesh(const SMESH_Mesh* theMesh,
+ const TopoDS_Shape& theShape)
+{
+ if ( !theMesh || theShape.IsNull() )
+ return false;
+
+ int nbEdges = 0;
+ TopTools_IndexedMapOfShape edgeMap;
+ TopExp::MapShapes( theShape, TopAbs_EDGE, edgeMap );
+
+ SMESH_MesherHelper helper( (SMESH_Mesh&) *theMesh );
+ double minSz2 = 1e100, maxSz2 = 0, sz2, maxDefl2 = 0;
+ for ( int iE = 1; iE <= edgeMap.Extent(); ++iE )
+ {
+ const TopoDS_Edge& edge = TopoDS::Edge( edgeMap( iE ));
+ SMESHDS_SubMesh* smDS = theMesh->GetMeshDS()->MeshElements( edge );
+ if ( !smDS ) continue;
+ ++nbEdges;
+
+ helper.SetSubShape( edge );
+ BRepAdaptor_Curve curve( edge );
+
+ SMDS_ElemIteratorPtr segIt = smDS->GetElements();
+ while ( segIt->more() )
+ {
+ const SMDS_MeshElement* seg = segIt->next();
+ const SMDS_MeshNode* n1 = seg->GetNode(0);
+ const SMDS_MeshNode* n2 = seg->GetNode(1);
+ sz2 = SMESH_TNodeXYZ( n1 ).SquareDistance( n2 );
+ minSz2 = Min( minSz2, sz2 );
+ maxSz2 = Max( maxSz2, sz2 );
+ if ( curve.GetType() != GeomAbs_Line )
+ {
+ double u1 = helper.GetNodeU( edge, n1, n2 );
+ double u2 = helper.GetNodeU( edge, n2, n1 );
+ maxDefl2 = Max( maxDefl2, deflection2( curve, u1, u2 ));
+ }
+ }
+ }
+ if ( nbEdges )
+ {
+ myMinSize = sqrt( minSz2 );
+ myMaxSize = sqrt( maxSz2 );
+ if ( maxDefl2 > 0 )
+ myDeflection = maxDefl2;
+ }
+ return nbEdges;
+}
+
+//=======================================================================
+//function : SetParametersByDefaults
+//purpose : Initialize my parameter values by default parameters.
+//retval : bool - true if parameter values have been successfully defined
+bool StdMeshers_Adaptive1D::SetParametersByDefaults(const TDefaults& dflts,
+ const SMESH_Mesh* /*theMesh*/)
+{
+ myMinSize = dflts._elemLength / 100;
+ myMaxSize = dflts._elemLength * 2;
+ myDeflection = myMinSize / 10;
+ return true;
+}
+
+//=======================================================================
+//function : GetAlgo
+//purpose : Returns an algorithm that works using this hypothesis
+//=======================================================================
+
+StdMeshers_AdaptiveAlgo_1D* StdMeshers_Adaptive1D::GetAlgo() const
+{
+ if ( !myAlgo )
+ {
+ StdMeshers_AdaptiveAlgo_1D* newAlgo =
+ new StdMeshers_AdaptiveAlgo_1D( _gen->GetANewId(), _studyId, _gen );
+ newAlgo->SetHypothesis( this );
+
+ ((StdMeshers_Adaptive1D*) this)->myAlgo = newAlgo;
+ }
+ return myAlgo;
+}
+
+//================================================================================
+/*!
+ * \brief Constructor
+ */
+//================================================================================
+
+StdMeshers_AdaptiveAlgo_1D::StdMeshers_AdaptiveAlgo_1D(int hypId,
+ int studyId,
+ SMESH_Gen* gen)
+ : StdMeshers_Regular_1D( hypId, studyId, gen ),
+ myHyp(NULL)
+{
+ _name = "AdaptiveAlgo_1D";
+}
+
+//================================================================================
+/*!
+ * \brief Sets the hypothesis
+ */
+//================================================================================
+
+void StdMeshers_AdaptiveAlgo_1D::SetHypothesis( const StdMeshers_Adaptive1D* hyp )
+{
+ myHyp = hyp;
+}
+
+//================================================================================
+/*!
+ * \brief Creates segments on all given EDGEs
+ */
+//================================================================================
+
+bool StdMeshers_AdaptiveAlgo_1D::Compute(SMESH_Mesh & theMesh,
+ const TopoDS_Shape & theShape,
+ double* theProgress,
+ int* theProgressTic)
+{
+ *theProgress = 0.01;
+
+ if ( myHyp->GetMinSize() > myHyp->GetMaxSize() )
+ return error( "Bad parameters: min size > max size" );
+
+ SMESH_MesherHelper helper( theMesh );
+ const double grading = 0.7;
+
+ TopTools_IndexedMapOfShape edgeMap, faceMap;
+ TopExp::MapShapes( theShape, TopAbs_EDGE, edgeMap );
+ TopExp::MapShapes( theMesh.GetShapeToMesh(), TopAbs_FACE, faceMap );
+
+ // Triangulate the shape with the given deflection ?????????
+ Bnd_B3d box;
+ {
+ IncrementalMesh im( theMesh.GetShapeToMesh(), myHyp->GetDeflection(), /*Relatif=*/false);
+ box = im.GetBox();
+ }
+ *theProgress = 0.3;
+
+ // holder of segment size at each point
+ SegSizeTree sizeTree( box, grading, myHyp->GetMinSize(), myHyp->GetMaxSize() );
+
+ // minimal segment size that sizeTree can store with reasonable tree height
+ const double minSize = Max( myHyp->GetMinSize(), 1.1 * sizeTree.GetMinSize() );
+
+
+ // working data of EDGEs
+ vector< EdgeData > edges;
+ {
+ // sort EDGEs by length
+ multimap< double, TopoDS_Edge > edgeOfLength;
+ for ( int iE = 1; iE <= edgeMap.Extent(); ++iE )
+ {
+ const TopoDS_Edge & edge = TopoDS::Edge( edgeMap( iE ));
+ if ( !SMESH_Algo::isDegenerated( edge) )
+ edgeOfLength.insert( make_pair( EdgeLength( edge ), edge ));
+ }
+ edges.resize( edgeOfLength.size() );
+ multimap< double, TopoDS_Edge >::const_iterator len2edge = edgeOfLength.begin();
+ for ( int iE = 0; len2edge != edgeOfLength.end(); ++len2edge, ++iE )
+ {
+ const TopoDS_Edge & edge = len2edge->second;
+ EdgeData& eData = edges[ iE ];
+ eData.myC3d.Initialize( edge );
+ eData.myLength = EdgeLength( edge );
+ eData.AddPoint( eData.myPoints.end(), eData.myC3d.FirstParameter() );
+ eData.AddPoint( eData.myPoints.end(), eData.myC3d.LastParameter() );
+ }
+ }
+
+ // Take into account size of already existing segments
+ SMDS_EdgeIteratorPtr segIterator = theMesh.GetMeshDS()->edgesIterator();
+ while ( segIterator->more() )
+ {
+ const SMDS_MeshElement* seg = segIterator->next();
+ sizeTree.SetSize( SMESH_TNodeXYZ( seg->GetNode( 0 )), SMESH_TNodeXYZ( seg->GetNode( 1 )));
+ }
+
+ // Set size of segments according to the deflection
+
+ StdMeshers_Regular_1D::_hypType = DEFLECTION;
+ StdMeshers_Regular_1D::_value[ DEFLECTION_IND ] = myHyp->GetDeflection();
+
+ list< double > params;
+ for ( int iE = 0; iE < edges.size(); ++iE )
+ {
+ EdgeData& eData = edges[ iE ];
+ //cout << "E " << theMesh.GetMeshDS()->ShapeToIndex( eData.Edge() ) << endl;
+
+ double f = eData.First().myU, l = eData.Last().myU;
+ if ( !computeInternalParameters( theMesh, eData.myC3d, eData.myLength, f,l, params, false, false ))
+ continue;
+ if ( params.size() <= 1 && helper.IsClosedEdge( eData.Edge() ) ) // 2 segments on a circle
+ {
+ params.clear();
+ for ( int i = 1; i < 6; ++i )
+ params.push_back(( l - f ) * i/6. );
+ }
+ EdgeData::TPntIter where = --eData.myPoints.end();
+ list< double >::const_iterator param = params.begin();
+ for ( ; param != params.end(); ++param )
+ eData.AddPoint( where, *param );
+
+ EdgeData::TPntIter pIt2 = eData.myPoints.begin(), pIt1 = pIt2++;
+ for ( ; pIt2 != eData.myPoints.end(); ++pIt1, ++pIt2 )
+ sizeTree.SetSize( (*pIt1).myP, (*pIt2).myP );
+ }
+
+ // Limit size of segments according to distance to closest FACE
+
+ for ( int iF = 1; iF <= faceMap.Extent(); ++iF )
+ {
+ const TopoDS_Face & face = TopoDS::Face( faceMap( iF ));
+ // cout << "FACE " << iF << "/" << faceMap.Extent()
+ // << " id-" << theMesh.GetMeshDS()->ShapeToIndex( face ) << endl;
+
+ ElementBndBoxTree triaTree( face ); // tree of FACE triangulation
+ TriaTreeData* triaSearcher = triaTree.GetTriaData();
+
+ if ( BRepAdaptor_Surface( face ).GetType() != GeomAbs_Plane )
+ triaSearcher->SetSizeByTrias( sizeTree, myHyp->GetDeflection() );
+
+ for ( int iE = 0; iE < edges.size(); ++iE )
+ {
+ EdgeData& eData = edges[ iE ];
+
+ // check if the face is in topological contact with the edge
+ bool isAdjFace = ( helper.IsSubShape( helper.IthVertex( 0, eData.Edge()), face ) ||
+ helper.IsSubShape( helper.IthVertex( 1, eData.Edge()), face ));
+
+ bool sizeDecreased = true;
+ for (int iLoop = 0; sizeDecreased; ++iLoop ) //repeat until segment size along the edge becomes stable
+ {
+ // get points to check distance to the face
+ EdgeData::TPntIter pIt2 = eData.myPoints.begin(), pIt1 = pIt2++;
+ pIt1->mySegSize = sizeTree.GetSize( pIt1->myP );
+ for ( ; pIt2 != eData.myPoints.end(); )
+ {
+ pIt2->mySegSize = sizeTree.GetSize( pIt2->myP );
+ double curSize = Min( pIt1->mySegSize, pIt2->mySegSize );
+ if ( pIt1->myP.Distance( pIt2->myP ) > curSize )
+ {
+ double midU = 0.5*( pIt1->myU + pIt2->myU );
+ gp_Pnt midP = eData.myC3d.Value( midU );
+ double midSz = sizeTree.GetSize( midP );
+ pIt2 = eData.myPoints.insert( pIt2, EdgeData::ProbePnt( midP, midU, midSz ));
+ }
+ else
+ {
+ ++pIt1, ++pIt2;
+ }
+ }
+ // check if the face is more distant than a half of the current segment size,
+ // if not, segment size is decreased
+ sizeDecreased = false;
+ const gp_Pnt* avoidPnt = & eData.First().myP;
+ for ( pIt1 = eData.myPoints.begin(); pIt1 != eData.myPoints.end(); )
+ {
+ double distToFace =
+ triaSearcher->GetMinDistInSphere( pIt1->myP, pIt1->mySegSize, isAdjFace, avoidPnt );
+ double allowedSize = Max( minSize, distToFace*( 1. + grading ));
+ if ( 1.1 * allowedSize < pIt1->mySegSize )
+ {
+ sizeDecreased = true;
+ sizeTree.SetSize( pIt1->myP, allowedSize );
+ // cout << "E " << theMesh.GetMeshDS()->ShapeToIndex( eData.Edge() )
+ // << "\t SetSize " << allowedSize << " at "
+ // << pIt1->myP.X() <<", "<< pIt1->myP.Y()<<", "<myP.Z() << endl;
+ pIt2 = pIt1;
+ if ( --pIt2 != eData.myPoints.end() && pIt2->mySegSize > allowedSize )
+ sizeTree.SetSize( eData.myC3d.Value( 0.6*pIt2->myU + 0.4*pIt1->myU ), allowedSize );
+ pIt2 = pIt1;
+ if ( ++pIt2 != eData.myPoints.end() && pIt2->mySegSize > allowedSize )
+ sizeTree.SetSize( eData.myC3d.Value( 0.6*pIt2->myU + 0.4*pIt1->myU ), allowedSize );
+ pIt1->mySegSize = allowedSize;
+ }
+ ++pIt1;
+ if ( & (*pIt1) == & eData.Last() )
+ avoidPnt = & eData.Last().myP;
+ else
+ avoidPnt = NULL;
+
+ if ( iLoop > 20 )
+ {
+#ifdef _DEBUG_
+ cout << "Infinite loop in StdMeshers_AdaptiveAlgo_1D::Compute()" << endl;
+#endif
+ sizeDecreased = false;
+ break;
+ }
+ }
+ } // while ( sizeDecreased )
+ } // loop on edges
+
+ *theProgress = 0.3 + 0.3 * iF / double( faceMap.Extent() );
+ if ( _computeCanceled )
+ return false;
+
+ } // loop on faceMap
+
+
+ // Create segments
+
+ SMESH_HypoFilter quadHyp( SMESH_HypoFilter::HasName( "QuadraticMesh" ));
+ _quadraticMesh = theMesh.GetHypothesis( edges[0].Edge(), quadHyp, /*andAncestors=*/true );
+ helper.SetIsQuadratic( _quadraticMesh );
+
+ for ( int iE = 0; iE < edges.size(); ++iE )
+ {
+ EdgeData& eData = edges[ iE ];
+
+ // estimate roughly min segement size on the EDGE
+ double edgeMinSize = myHyp->GetMaxSize();
+ EdgeData::TPntIter pIt1 = eData.myPoints.begin();
+ for ( ; pIt1 != eData.myPoints.end(); ++pIt1 )
+ edgeMinSize = Min( edgeMinSize, sizeTree.GetSize( pIt1->myP ));
+
+ const double f = eData.myC3d.FirstParameter(), l = eData.myC3d.LastParameter();
+ const double parLen = l - f;
+ const int nbDivSeg = 5;
+ int nbDiv = int ( eData.myLength / edgeMinSize * nbDivSeg );
+
+ // compute nb of segments
+ vector< double > nbSegs;
+ bool toRecompute = true;
+ double maxSegSize = 0;
+ //cout << "E " << theMesh.GetMeshDS()->ShapeToIndex( eData.Edge() ) << endl;
+ while ( toRecompute ) // recompute if segment size at some point is less than edgeMinSize/nbDivSeg
+ {
+ nbSegs.resize( nbDiv + 1 );
+ nbSegs[0] = 0;
+ toRecompute = false;
+
+ gp_Pnt p1 = eData.First().myP, p2, pDiv = p1;
+ for ( size_t i = 1, segCount = 1; i < nbSegs.size(); ++i )
+ {
+ p2 = eData.myC3d.Value( f + parLen * i / nbDiv );
+ double locSize = Min( sizeTree.GetSize( p2 ), myHyp->GetMaxSize() );
+ double nb = p1.Distance( p2 ) / locSize;
+ // if ( nbSegs.size() < 30 )
+ // cout << "locSize " << locSize << " nb " << nb << endl;
+ if ( nb > 1. )
+ {
+ toRecompute = true;
+ edgeMinSize = locSize;
+ nbDiv = int ( eData.myLength / edgeMinSize * nbDivSeg );
+ break;
+ }
+ nbSegs[i] = nbSegs[i-1] + nb;
+ p1 = p2;
+ if ( nbSegs[i] >= segCount )
+ {
+ maxSegSize = Max( maxSegSize, pDiv.Distance( p2 ));
+ pDiv = p2;
+ ++segCount;
+ }
+ }
+ }
+
+ // compute parameters of nodes
+ int nbSegFinal = int(floor(nbSegs.back()+0.5));
+ double fact = nbSegFinal / nbSegs.back();
+ if ( maxSegSize / fact > myHyp->GetMaxSize() )
+ fact = ++nbSegFinal / nbSegs.back();
+ //cout << "nbSegs.back() " << nbSegs.back() << " nbSegFinal " << nbSegFinal << endl;
+ params.clear();
+ for ( int i = 0, segCount = 1; segCount < nbSegFinal; ++segCount )
+ {
+ while ( nbSegs[i] * fact < segCount )
+ ++i;
+ if ( i < nbDiv )
+ params.push_back( f + parLen * i / nbDiv );
+ else
+ break;
+ }
+ // get nodes on VERTEXes
+ TopoDS_Vertex vf = helper.IthVertex( 0, eData.Edge(), false );
+ TopoDS_Vertex vl = helper.IthVertex( 1, eData.Edge(), false );
+ theMesh.GetSubMesh( vf )->ComputeStateEngine( SMESH_subMesh::COMPUTE );
+ theMesh.GetSubMesh( vl )->ComputeStateEngine( SMESH_subMesh::COMPUTE );
+ const SMDS_MeshNode * nf = VertexNode( vf, theMesh.GetMeshDS() );
+ const SMDS_MeshNode * nl = VertexNode( vl, theMesh.GetMeshDS() );
+ if ( !nf || !nl )
+ return error("No node on vertex");
+
+ // create segments
+ helper.SetSubShape( eData.Edge() );
+ helper.SetElementsOnShape( true );
+ const int ID = 0;
+ const SMDS_MeshNode *n1 = nf, *n2;
+ list< double >::const_iterator u = params.begin();
+ for ( ; u != params.end(); ++u, n1 = n2 )
+ {
+ gp_Pnt p2 = eData.myC3d.Value( *u );
+ n2 = helper.AddNode( p2.X(), p2.Y(), p2.Z(), ID, *u );
+ helper.AddEdge( n1, n2, ID, /*force3d=*/false );
+ }
+ helper.AddEdge( n1, nl, ID, /*force3d=*/false );
+
+ *theProgress = 0.6 + 0.4 * iE / double( edges.size() );
+ if ( _computeCanceled )
+ return false;
+
+ } // loop on EDGEs
+
+}
+
+
+//================================================================================
+/*!
+ * \brief Creates segments on all given EDGEs
+ */
+//================================================================================
+
+bool StdMeshers_AdaptiveAlgo_1D::Evaluate(SMESH_Mesh & theMesh,
+ const TopoDS_Shape & theShape,
+ MapShapeNbElems& theResMap)
+{
+ // initialize fields of inherited StdMeshers_Regular_1D
+ StdMeshers_Regular_1D::_hypType = DEFLECTION;
+ StdMeshers_Regular_1D::_value[ DEFLECTION_IND ] = myHyp->GetDeflection();
+
+ TopExp_Explorer edExp( theShape, TopAbs_EDGE );
+
+ for ( ; edExp.More(); edExp.Next() )
+ {
+ const TopoDS_Edge & edge = TopoDS::Edge( edExp.Current() );
+ StdMeshers_Regular_1D::Evaluate( theMesh, theShape, theResMap );
+ }
+ return true;
+}
+
diff --git a/src/StdMeshers/StdMeshers_Adaptive1D.hxx b/src/StdMeshers/StdMeshers_Adaptive1D.hxx
new file mode 100644
index 000000000..be5e329be
--- /dev/null
+++ b/src/StdMeshers/StdMeshers_Adaptive1D.hxx
@@ -0,0 +1,115 @@
+// Copyright (C) 2007-2013 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.
+//
+// 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 : StdMeshers_Adaptive1D.hxx
+// Module : SMESH
+//
+#ifndef _StdMeshers_Adaptive1D_HXX_
+#define _StdMeshers_Adaptive1D_HXX_
+
+#include "SMESH_StdMeshers.hxx"
+
+#include "StdMeshers_Regular_1D.hxx"
+
+#include "Utils_SALOME_Exception.hxx"
+
+class StdMeshers_AdaptiveAlgo_1D;
+
+/*!
+ * \brief Adaptive 1D hypothesis
+ */
+class STDMESHERS_EXPORT StdMeshers_Adaptive1D : public SMESH_Hypothesis
+{
+ public:
+ StdMeshers_Adaptive1D(int hypId, int studyId, SMESH_Gen * gen);
+ ~StdMeshers_Adaptive1D();
+
+ /*!
+ * Sets minimal allowed segment length
+ */
+ void SetMinSize( double minSegLen ) throw (SALOME_Exception);
+ double GetMinSize() const { return myMinSize; }
+
+ /*!
+ * Sets maximal allowed segment length
+ */
+ void SetMaxSize( double maxSegLen ) throw (SALOME_Exception);
+ double GetMaxSize() const { return myMaxSize; }
+
+ /*!
+ * Sets parameter value,
+ * i.e. a maximal allowed distance between a segment and an edge.
+ */
+ void SetDeflection(double value) throw(SALOME_Exception);
+ double GetDeflection() const { return myDeflection; }
+
+ virtual std::ostream & SaveTo(std::ostream & save);
+ virtual std::istream & LoadFrom(std::istream & load);
+
+ /*!
+ * \brief Initialize deflection value by the mesh built on the geometry
+ * \param theMesh - the built mesh
+ * \param theShape - the geometry of interest
+ * \retval bool - true if parameter values have been successfully defined
+ */
+ virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape);
+
+ /*!
+ * \brief Initialize my parameter values by default parameters.
+ * \retval bool - true if parameter values have been successfully defined
+ */
+ virtual bool SetParametersByDefaults(const TDefaults& dflts, const SMESH_Mesh* theMesh=0);
+
+ /*!
+ * \brief Returns an algorithm that works using this hypothesis
+ */
+ StdMeshers_AdaptiveAlgo_1D* GetAlgo() const;
+
+protected:
+
+ double myMinSize, myMaxSize, myDeflection;
+ StdMeshers_AdaptiveAlgo_1D* myAlgo;
+};
+
+/*!
+ * \brief Adaptive wire discertizator.
+ * This algorithm is not used directly by via StdMeshers_Regular_1D
+ */
+class StdMeshers_AdaptiveAlgo_1D : public StdMeshers_Regular_1D
+{
+public:
+
+ StdMeshers_AdaptiveAlgo_1D(int hypId, int studyId, SMESH_Gen* gen);
+
+ void SetHypothesis( const StdMeshers_Adaptive1D* hyp );
+
+ bool Compute(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape,
+ double* progress, int* progressTic );
+ virtual bool Evaluate(SMESH_Mesh & theMesh,
+ const TopoDS_Shape & theShape,
+ MapShapeNbElems& theResMap);
+
+private:
+
+ const StdMeshers_Adaptive1D* myHyp;
+};
+
+#endif
diff --git a/src/StdMeshers/StdMeshers_Regular_1D.cxx b/src/StdMeshers/StdMeshers_Regular_1D.cxx
index 303b4794b..cf4120437 100644
--- a/src/StdMeshers/StdMeshers_Regular_1D.cxx
+++ b/src/StdMeshers/StdMeshers_Regular_1D.cxx
@@ -26,11 +26,21 @@
// Module : SMESH
//
#include "StdMeshers_Regular_1D.hxx"
-#include "StdMeshers_Distribution.hxx"
+#include "SMDS_MeshElement.hxx"
+#include "SMDS_MeshNode.hxx"
+#include "SMESH_Comment.hxx"
+#include "SMESH_Gen.hxx"
+#include "SMESH_HypoFilter.hxx"
+#include "SMESH_Mesh.hxx"
+#include "SMESH_subMesh.hxx"
+#include "SMESH_subMeshEventListener.hxx"
+#include "StdMeshers_Adaptive1D.hxx"
#include "StdMeshers_Arithmetic1D.hxx"
#include "StdMeshers_AutomaticLength.hxx"
#include "StdMeshers_Deflection1D.hxx"
+#include "StdMeshers_Distribution.hxx"
+#include "StdMeshers_FixedPoints1D.hxx"
#include "StdMeshers_LocalLength.hxx"
#include "StdMeshers_MaxLength.hxx"
#include "StdMeshers_NumberOfSegments.hxx"
@@ -38,16 +48,6 @@
#include "StdMeshers_SegmentLengthAroundVertex.hxx"
#include "StdMeshers_StartEndLength.hxx"
-#include "SMESH_Gen.hxx"
-#include "SMESH_Mesh.hxx"
-#include "SMESH_HypoFilter.hxx"
-#include "SMESH_subMesh.hxx"
-#include "SMESH_subMeshEventListener.hxx"
-#include "SMESH_Comment.hxx"
-
-#include "SMDS_MeshElement.hxx"
-#include "SMDS_MeshNode.hxx"
-
#include "Utils_SALOME_Exception.hxx"
#include "utilities.h"
@@ -75,29 +75,31 @@ using namespace std;
//=============================================================================
StdMeshers_Regular_1D::StdMeshers_Regular_1D(int hypId, int studyId,
- SMESH_Gen * gen):SMESH_1D_Algo(hypId, studyId, gen)
+ SMESH_Gen * gen)
+ :SMESH_1D_Algo(hypId, studyId, gen)
{
- MESSAGE("StdMeshers_Regular_1D::StdMeshers_Regular_1D");
- _name = "Regular_1D";
- _shapeType = (1 << TopAbs_EDGE);
- _fpHyp = 0;
+ MESSAGE("StdMeshers_Regular_1D::StdMeshers_Regular_1D");
+ _name = "Regular_1D";
+ _shapeType = (1 << TopAbs_EDGE);
+ _fpHyp = 0;
- _compatibleHypothesis.push_back("LocalLength");
- _compatibleHypothesis.push_back("MaxLength");
- _compatibleHypothesis.push_back("NumberOfSegments");
- _compatibleHypothesis.push_back("StartEndLength");
- _compatibleHypothesis.push_back("Deflection1D");
- _compatibleHypothesis.push_back("Arithmetic1D");
- _compatibleHypothesis.push_back("FixedPoints1D");
- _compatibleHypothesis.push_back("AutomaticLength");
+ _compatibleHypothesis.push_back("LocalLength");
+ _compatibleHypothesis.push_back("MaxLength");
+ _compatibleHypothesis.push_back("NumberOfSegments");
+ _compatibleHypothesis.push_back("StartEndLength");
+ _compatibleHypothesis.push_back("Deflection1D");
+ _compatibleHypothesis.push_back("Arithmetic1D");
+ _compatibleHypothesis.push_back("FixedPoints1D");
+ _compatibleHypothesis.push_back("AutomaticLength");
+ _compatibleHypothesis.push_back("Adaptive1D");
- _compatibleHypothesis.push_back("QuadraticMesh"); // auxiliary !!!
- _compatibleHypothesis.push_back("Propagation"); // auxiliary !!!
+ _compatibleHypothesis.push_back("QuadraticMesh"); // auxiliary !!!
+ _compatibleHypothesis.push_back("Propagation"); // auxiliary !!!
}
//=============================================================================
/*!
- *
+ *
*/
//=============================================================================
@@ -111,13 +113,13 @@ StdMeshers_Regular_1D::~StdMeshers_Regular_1D()
*/
//=============================================================================
-bool StdMeshers_Regular_1D::CheckHypothesis
- (SMESH_Mesh& aMesh,
- const TopoDS_Shape& aShape,
- SMESH_Hypothesis::Hypothesis_Status& aStatus)
+bool StdMeshers_Regular_1D::CheckHypothesis( SMESH_Mesh& aMesh,
+ const TopoDS_Shape& aShape,
+ Hypothesis_Status& aStatus )
{
_hypType = NONE;
_quadraticMesh = false;
+ _onlyUnaryInput = true;
const list & hyps =
GetUsedHypothesis(aMesh, aShape, /*ignoreAuxiliaryHyps=*/false);
@@ -263,12 +265,17 @@ bool StdMeshers_Regular_1D::CheckHypothesis
(dynamic_cast (theHyp));
ASSERT(hyp);
_value[ BEG_LENGTH_IND ] = _value[ END_LENGTH_IND ] = hyp->GetLength( &aMesh, aShape );
-// _value[ BEG_LENGTH_IND ] = hyp->GetLength( &aMesh, aShape );
-// _value[ END_LENGTH_IND ] = Precision::Confusion(); // ?? or set to zero?
ASSERT( _value[ BEG_LENGTH_IND ] > 0 );
_hypType = MAX_LENGTH;
aStatus = SMESH_Hypothesis::HYP_OK;
}
+ else if (hypName == "Adaptive1D")
+ {
+ _adaptiveHyp = dynamic_cast < const StdMeshers_Adaptive1D* >(theHyp);
+ ASSERT(_adaptiveHyp);
+ _hypType = ADAPTIVE;
+ _onlyUnaryInput = false;
+ }
else
aStatus = SMESH_Hypothesis::HYP_INCOMPATIBLE;
@@ -950,6 +957,13 @@ bool StdMeshers_Regular_1D::Compute(SMESH_Mesh & theMesh, const TopoDS_Shape & t
if ( _hypType == NONE )
return false;
+ if ( _hypType == ADAPTIVE )
+ {
+ _adaptiveHyp->GetAlgo()->InitComputeError();
+ _adaptiveHyp->GetAlgo()->Compute( theMesh, theShape, &_progress, &_progressTic );
+ return error( _adaptiveHyp->GetAlgo()->GetComputeError() );
+ }
+
SMESHDS_Mesh * meshDS = theMesh.GetMeshDS();
const TopoDS_Edge & EE = TopoDS::Edge(theShape);
@@ -1128,11 +1142,15 @@ bool StdMeshers_Regular_1D::Evaluate(SMESH_Mesh & theMesh,
if ( _hypType == NONE )
return false;
- //SMESHDS_Mesh * meshDS = theMesh.GetMeshDS();
+ if ( _hypType == ADAPTIVE )
+ {
+ _adaptiveHyp->GetAlgo()->InitComputeError();
+ _adaptiveHyp->GetAlgo()->Evaluate( theMesh, theShape, aResMap );
+ return error( _adaptiveHyp->GetAlgo()->GetComputeError() );
+ }
const TopoDS_Edge & EE = TopoDS::Edge(theShape);
TopoDS_Edge E = TopoDS::Edge(EE.Oriented(TopAbs_FORWARD));
- // int shapeID = meshDS->ShapeToIndex( E );
double f, l;
Handle(Geom_Curve) Curve = BRep_Tool::Curve(E, f, l);
@@ -1237,3 +1255,16 @@ StdMeshers_Regular_1D::GetUsedHypothesis(SMESH_Mesh & aMesh,
return _usedHypList;
}
+
+//================================================================================
+/*!
+ * \brief Pass CancelCompute() to a child algorithm
+ */
+//================================================================================
+
+void StdMeshers_Regular_1D::CancelCompute()
+{
+ SMESH_Algo::CancelCompute();
+ if ( _hypType == ADAPTIVE )
+ _adaptiveHyp->GetAlgo()->CancelCompute();
+}
diff --git a/src/StdMeshers/StdMeshers_Regular_1D.hxx b/src/StdMeshers/StdMeshers_Regular_1D.hxx
index e536aa3d9..1551affd6 100644
--- a/src/StdMeshers/StdMeshers_Regular_1D.hxx
+++ b/src/StdMeshers/StdMeshers_Regular_1D.hxx
@@ -33,11 +33,12 @@
#include "SMESH_Algo.hxx"
-#include "StdMeshers_FixedPoints1D.hxx"
-
class Adaptor3d_Curve;
-class TopoDS_Vertex;
+class StdMeshers_Adaptive1D;
+class StdMeshers_AdaptiveAlgo_1D;
+class StdMeshers_FixedPoints1D;
class StdMeshers_SegmentLengthAroundVertex;
+class TopoDS_Vertex;
class STDMESHERS_EXPORT StdMeshers_Regular_1D: public SMESH_1D_Algo
{
@@ -55,6 +56,8 @@ public:
virtual bool Evaluate(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape,
MapShapeNbElems& aResMap);
+ virtual void CancelCompute();
+
virtual const std::list &
GetUsedHypothesis(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape, const bool=true);
@@ -100,7 +103,7 @@ protected:
StdMeshers_SegmentLengthAroundVertex* getVertexHyp(SMESH_Mesh & theMesh,
const TopoDS_Vertex & theV);
- enum HypothesisType { LOCAL_LENGTH, MAX_LENGTH, NB_SEGMENTS, BEG_END_LENGTH, DEFLECTION, ARITHMETIC_1D, FIXED_POINTS_1D, NONE };
+ enum HypothesisType { LOCAL_LENGTH, MAX_LENGTH, NB_SEGMENTS, BEG_END_LENGTH, DEFLECTION, ARITHMETIC_1D, FIXED_POINTS_1D, ADAPTIVE, NONE };
enum ValueIndex {
SCALE_FACTOR_IND = 0,
@@ -111,9 +114,9 @@ protected:
};
enum IValueIndex {
- NB_SEGMENTS_IND = 0,
- DISTR_TYPE_IND = 1,
- CONV_MODE_IND = 2
+ NB_SEGMENTS_IND = 0,
+ DISTR_TYPE_IND = 1,
+ CONV_MODE_IND = 2
};
enum VValueIndex {
@@ -127,6 +130,8 @@ protected:
HypothesisType _hypType;
const StdMeshers_FixedPoints1D* _fpHyp;
+ const StdMeshers_Adaptive1D* _adaptiveHyp;
+ StdMeshers_AdaptiveAlgo_1D* getAdaptiveAlgo();
double _value[2];
int _ivalue[3];
diff --git a/src/StdMeshersGUI/StdMeshersGUI_StdHypothesisCreator.cxx b/src/StdMeshersGUI/StdMeshersGUI_StdHypothesisCreator.cxx
index 493235b15..ca774d105 100644
--- a/src/StdMeshersGUI/StdMeshersGUI_StdHypothesisCreator.cxx
+++ b/src/StdMeshersGUI/StdMeshersGUI_StdHypothesisCreator.cxx
@@ -582,6 +582,17 @@ QString StdMeshersGUI_StdHypothesisCreator::storeParams() const
h->SetVarParameter( params[0].text(), "SetDeflection" );
h->SetDeflection( params[0].myValue.toDouble() );
}
+ else if( hypType()=="Adaptive1D" )
+ {
+ StdMeshers::StdMeshers_Adaptive1D_var h =
+ StdMeshers::StdMeshers_Adaptive1D::_narrow( hypothesis() );
+ h->SetVarParameter( params[0].text(), "SetMinSize" );
+ h->SetMinSize( params[0].myValue.toDouble() );
+ h->SetVarParameter( params[0].text(), "SetMaxSize" );
+ h->SetMaxSize( params[1].myValue.toDouble() );
+ h->SetVarParameter( params[0].text(), "SetDeflection" );
+ h->SetDeflection( params[2].myValue.toDouble() );
+ }
else if( hypType()=="AutomaticLength" )
{
StdMeshers::StdMeshers_AutomaticLength_var h =
@@ -960,7 +971,27 @@ bool StdMeshersGUI_StdHypothesisCreator::stdParams( ListOfStdParams& p ) const
{
StdMeshers::StdMeshers_Deflection1D_var h =
StdMeshers::StdMeshers_Deflection1D::_narrow( hyp );
-
+
+ item.myName = tr( "SMESH_DEFLECTION1D_PARAM" );
+ if(!initVariableName( hyp, item, "SetDeflection" ))
+ item.myValue = h->GetDeflection();
+ p.append( item );
+ }
+ else if( hypType()=="Adaptive1D" )
+ {
+ StdMeshers::StdMeshers_Adaptive1D_var h =
+ StdMeshers::StdMeshers_Adaptive1D::_narrow( hyp );
+
+ item.myName = tr( "SMESH_MIN_SIZE" );
+ if(!initVariableName( hyp, item, "SetMinSize" ))
+ item.myValue = h->GetMinSize();
+ p.append( item );
+
+ item.myName = tr( "SMESH_MAX_SIZE" );
+ if(!initVariableName( hyp, item, "SetMaxSize" ))
+ item.myValue = h->GetMaxSize();
+ p.append( item );
+
item.myName = tr( "SMESH_DEFLECTION1D_PARAM" );
if(!initVariableName( hyp, item, "SetDeflection" ))
item.myValue = h->GetDeflection();
@@ -1315,6 +1346,10 @@ void StdMeshersGUI_StdHypothesisCreator::attuneStdWidget (QWidget* w, const int)
{
sb->RangeStepAndValidator( VALUE_SMALL, VALUE_MAX, 1.0, "parametric_precision" );
}
+ else if( hypType()=="Adaptive1D" )
+ {
+ sb->RangeStepAndValidator( VALUE_SMALL, VALUE_MAX, 1.0, "length_precision" );
+ }
else if( hypType().startsWith( "ViscousLayers" ))
{
if (sb->objectName() == tr("SMESH_STRETCH_FACTOR"))
@@ -1386,6 +1421,7 @@ QString StdMeshersGUI_StdHypothesisCreator::hypTypeName( const QString& t ) cons
types.insert( "MaxElementVolume", "MAX_ELEMENT_VOLUME" );
types.insert( "StartEndLength", "START_END_LENGTH" );
types.insert( "Deflection1D", "DEFLECTION1D" );
+ types.insert( "Adaptive1D", "ADAPTIVE1D" );
types.insert( "Arithmetic1D", "ARITHMETIC_1D" );
types.insert( "FixedPoints1D", "FIXED_POINTS_1D" );
types.insert( "AutomaticLength", "AUTOMATIC_LENGTH" );
diff --git a/src/StdMeshersGUI/StdMeshers_images.ts b/src/StdMeshersGUI/StdMeshers_images.ts
index aaf16607c..a729340e2 100644
--- a/src/StdMeshersGUI/StdMeshers_images.ts
+++ b/src/StdMeshersGUI/StdMeshers_images.ts
@@ -19,6 +19,10 @@
ICON_DLG_DEFLECTION1D
mesh_hypo_length.png
+
+ ICON_DLG_ADAPTIVE1D
+ mesh_hypo_length.png
+
ICON_DLG_GEOMETRIC_1D
mesh_hypo_length.png
@@ -167,6 +171,10 @@
ICON_SMESH_TREE_HYPO_Deflection1D
mesh_tree_hypo_length.png
+
+ ICON_SMESH_TREE_HYPO_Adaptive1D
+ mesh_tree_hypo_length.png
+
ICON_SMESH_TREE_HYPO_LayerDistribution
mesh_tree_hypo_layers_distribution.png
diff --git a/src/StdMeshersGUI/StdMeshers_msg_en.ts b/src/StdMeshersGUI/StdMeshers_msg_en.ts
index cfc5d535d..c9982405e 100644
--- a/src/StdMeshersGUI/StdMeshers_msg_en.ts
+++ b/src/StdMeshersGUI/StdMeshers_msg_en.ts
@@ -46,6 +46,22 @@
SMESH_CUT_NEG_MODE
Cut negative
+
+ SMESH_ADAPTIVE1D_HYPOTHESIS
+ Adaptive
+
+
+ SMESH_MIN_SIZE
+ Min size
+
+
+ SMESH_MAX_SIZE
+ Max size
+
+
+ SMESH_ADAPTIVE1D_TITLE
+ Hypothesis Construction
+
SMESH_DEFLECTION1D_HYPOTHESIS
Deflection 1D
diff --git a/src/StdMeshers_I/CMakeLists.txt b/src/StdMeshers_I/CMakeLists.txt
index be2903f91..51cbd0c0d 100644
--- a/src/StdMeshers_I/CMakeLists.txt
+++ b/src/StdMeshers_I/CMakeLists.txt
@@ -170,6 +170,7 @@ SET(StdMeshersEngine_SOURCES
StdMeshers_ViscousLayers2D_i.cxx
StdMeshers_CartesianParameters3D_i.cxx
StdMeshers_Cartesian_3D_i.cxx
+ StdMeshers_Adaptive1D_i.cxx
)
IF(SALOME_SMESH_ENABLE_MEFISTO)
diff --git a/src/StdMeshers_I/StdMeshers_Adaptive1D_i.cxx b/src/StdMeshers_I/StdMeshers_Adaptive1D_i.cxx
new file mode 100644
index 000000000..99bc768ed
--- /dev/null
+++ b/src/StdMeshers_I/StdMeshers_Adaptive1D_i.cxx
@@ -0,0 +1,173 @@
+// Copyright (C) 2007-2013 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.
+//
+// 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 : StdMeshers_Adaptive1D_i.cxx
+// Module : SMESH
+//
+
+#include "StdMeshers_Adaptive1D_i.hxx"
+#include "SMESH_Gen_i.hxx"
+#include "SMESH_Gen.hxx"
+#include "SMESH_PythonDump.hxx"
+
+#include "StdMeshers_Adaptive1D.hxx"
+
+#include "Utils_CorbaException.hxx"
+#include "utilities.h"
+
+//=======================================================================
+//function : StdMeshers_Adaptive1D_i
+//purpose : Constructor
+//=======================================================================
+
+StdMeshers_Adaptive1D_i::StdMeshers_Adaptive1D_i( PortableServer::POA_ptr thePOA,
+ int theStudyId,
+ ::SMESH_Gen* theGenImpl )
+ : SALOME::GenericObj_i( thePOA ),
+ SMESH_Hypothesis_i( thePOA )
+{
+ myBaseImpl = new ::StdMeshers_Adaptive1D( theGenImpl->GetANewId(),
+ theStudyId,
+ theGenImpl );
+}
+
+//=======================================================================
+//function : ~StdMeshers_Adaptive1D_i
+//purpose : Destructor
+//=======================================================================
+
+StdMeshers_Adaptive1D_i::~StdMeshers_Adaptive1D_i()
+{
+ MESSAGE( "StdMeshers_Adaptive1D_i::~StdMeshers_Adaptive1D_i" );
+}
+
+//=======================================================================
+//function : SetMinSize
+//purpose : Sets minimal allowed segment length
+//=======================================================================
+
+void StdMeshers_Adaptive1D_i::SetMinSize( CORBA::Double minSegLen )
+ throw (SALOME::SALOME_Exception)
+{
+ ASSERT( myBaseImpl );
+ try {
+ this->GetImpl()->SetMinSize( minSegLen );
+ }
+ catch ( SALOME_Exception& S_ex ) {
+ THROW_SALOME_CORBA_EXCEPTION( S_ex.what(), SALOME::BAD_PARAM );
+ }
+
+ // Update Python script
+ SMESH::TPythonDump() << _this() << ".SetMinSize( " << SMESH::TVar(minSegLen) << " )";
+}
+
+//=======================================================================
+//function : GetMinSize
+//purpose : Returns minimal allowed segment length
+//=======================================================================
+
+CORBA::Double StdMeshers_Adaptive1D_i::GetMinSize()
+{
+ ASSERT( myBaseImpl );
+ return this->GetImpl()->GetMinSize();
+}
+
+//=======================================================================
+//function : SetMaxSize
+//purpose : Sets maximal allowed segment length
+//=======================================================================
+
+void StdMeshers_Adaptive1D_i::SetMaxSize( CORBA::Double maxSegLen )
+ throw (SALOME::SALOME_Exception)
+{
+ ASSERT( myBaseImpl );
+ try {
+ this->GetImpl()->SetMaxSize( maxSegLen );
+ }
+ catch ( SALOME_Exception& S_ex ) {
+ THROW_SALOME_CORBA_EXCEPTION( S_ex.what(), SALOME::BAD_PARAM );
+ }
+
+ // Update Python script
+ SMESH::TPythonDump() << _this() << ".SetMaxSize( " << SMESH::TVar(maxSegLen) << " )";
+}
+
+//=======================================================================
+//function : GetMaxSize
+//purpose : Returns maximal allowed segment length
+//=======================================================================
+
+CORBA::Double StdMeshers_Adaptive1D_i::GetMaxSize()
+{
+ ASSERT( myBaseImpl );
+ return this->GetImpl()->GetMaxSize();
+}
+
+//=======================================================================
+//function : SetDeflection
+//purpose : Sets a maximal allowed distance between a segment and an edge.
+//=======================================================================
+
+void StdMeshers_Adaptive1D_i::SetDeflection( CORBA::Double theValue )
+ throw ( SALOME::SALOME_Exception )
+{
+ ASSERT( myBaseImpl );
+ try {
+ this->GetImpl()->SetDeflection( theValue );
+ }
+ catch ( SALOME_Exception& S_ex ) {
+ THROW_SALOME_CORBA_EXCEPTION( S_ex.what(), SALOME::BAD_PARAM );
+ }
+
+ // Update Python script
+ SMESH::TPythonDump() << _this() << ".SetDeflection( " << SMESH::TVar(theValue) << " )";
+}
+
+//=======================================================================
+//function : GetDeflection
+//purpose : Returns deflection
+//=======================================================================
+
+CORBA::Double StdMeshers_Adaptive1D_i::GetDeflection()
+{
+ ASSERT( myBaseImpl );
+ return this->GetImpl()->GetDeflection();
+}
+
+//=======================================================================
+//function : GetImpl
+//purpose : Get implementation
+//=======================================================================
+
+::StdMeshers_Adaptive1D* StdMeshers_Adaptive1D_i::GetImpl()
+{
+ return ( ::StdMeshers_Adaptive1D* )myBaseImpl;
+}
+
+//=======================================================================
+//function : IsDimSupported
+//purpose : Verify whether hypothesis supports given entity type
+//=======================================================================
+
+CORBA::Boolean StdMeshers_Adaptive1D_i::IsDimSupported( SMESH::Dimension type )
+{
+ return type == SMESH::DIM_1D;
+}
diff --git a/src/StdMeshers_I/StdMeshers_Adaptive1D_i.hxx b/src/StdMeshers_I/StdMeshers_Adaptive1D_i.hxx
new file mode 100644
index 000000000..ac168ec72
--- /dev/null
+++ b/src/StdMeshers_I/StdMeshers_Adaptive1D_i.hxx
@@ -0,0 +1,89 @@
+// Copyright (C) 2007-2013 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.
+//
+// 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 : StdMeshers_Adaptive1D_i.hxx
+// Module : SMESH
+//
+#ifndef _SMESH_Adaptive1D_I_HXX_
+#define _SMESH_Adaptive1D_I_HXX_
+
+#include "SMESH_StdMeshers_I.hxx"
+
+#include
+#include CORBA_SERVER_HEADER(SMESH_BasicHypothesis)
+
+#include "SMESH_Hypothesis_i.hxx"
+
+class StdMeshers_Adaptive1D;
+class SMESH_Gen;
+
+// ======================================================
+// Adaptive1D hypothesis
+// ======================================================
+
+class STDMESHERS_I_EXPORT StdMeshers_Adaptive1D_i:
+ public virtual POA_StdMeshers::StdMeshers_Adaptive1D,
+ public virtual SMESH_Hypothesis_i
+{
+ public:
+ // Constructor
+ StdMeshers_Adaptive1D_i( PortableServer::POA_ptr thePOA,
+ int theStudyId,
+ ::SMESH_Gen* theGenImpl );
+ // Destructor
+ virtual ~StdMeshers_Adaptive1D_i();
+
+ /*!
+ * Sets minimal allowed segment length
+ */
+ void SetMinSize( CORBA::Double minSegLen ) throw (SALOME::SALOME_Exception);
+ CORBA::Double GetMinSize();
+
+ /*!
+ * Sets maximal allowed segment length
+ */
+ void SetMaxSize( CORBA::Double maxSegLen ) throw (SALOME::SALOME_Exception);
+ CORBA::Double GetMaxSize();
+
+ /*!
+ * Sets parameter value,
+ * i.e. a maximal allowed distance between a segment and an edge.
+ */
+ void SetDeflection( CORBA::Double theLength ) throw (SALOME::SALOME_Exception);
+ CORBA::Double GetDeflection();
+
+
+ /*!
+ * Returns implementation
+ */
+ ::StdMeshers_Adaptive1D* GetImpl();
+
+ /*!
+ * \brief Verify whether hypothesis supports given entity type
+ * \param type - dimension (see SMESH::Dimension enumeration)
+ * \retval CORBA::Boolean - TRUE if dimension is supported, FALSE otherwise
+ *
+ * Verify whether hypothesis supports given entity type (see SMESH::Dimension enumeration)
+ */
+ CORBA::Boolean IsDimSupported( SMESH::Dimension type );
+};
+
+#endif
diff --git a/src/StdMeshers_I/StdMeshers_i.cxx b/src/StdMeshers_I/StdMeshers_i.cxx
index a13257107..3cc3ac050 100644
--- a/src/StdMeshers_I/StdMeshers_i.cxx
+++ b/src/StdMeshers_I/StdMeshers_i.cxx
@@ -38,6 +38,7 @@
#include "StdMeshers_FixedPoints1D_i.hxx"
#include "StdMeshers_NumberOfSegments_i.hxx"
#include "StdMeshers_Deflection1D_i.hxx"
+#include "StdMeshers_Adaptive1D_i.hxx"
#include "StdMeshers_Propagation_i.hxx"
#include "StdMeshers_LengthFromEdges_i.hxx"
#include "StdMeshers_QuadranglePreference_i.hxx"
@@ -143,6 +144,8 @@ STDMESHERS_I_EXPORT
aCreator = new StdHypothesisCreator_i;
else if (strcmp(aHypName, "Deflection1D") == 0)
aCreator = new StdHypothesisCreator_i;
+ else if (strcmp(aHypName, "Adaptive1D") == 0)
+ aCreator = new StdHypothesisCreator_i;
else if (strcmp(aHypName, "FixedPoints1D") == 0)
aCreator = new StdHypothesisCreator_i;
else if (strcmp(aHypName, "Arithmetic1D") == 0)