diff --git a/doc/salome/examples/cartesian_algo.py b/doc/salome/examples/cartesian_algo.py
index dc0dc23cf..e5651cb67 100644
--- a/doc/salome/examples/cartesian_algo.py
+++ b/doc/salome/examples/cartesian_algo.py
@@ -50,3 +50,40 @@ print "nb hexahedra",mesh.NbHexas()
print "nb tetrahedra",mesh.NbTetras()
print "nb polyhedra",mesh.NbPolyhedrons()
print
+
+# Example of customization of dirtections of the grid axes
+
+# make a box with non-orthogonal edges
+xDir = geompy.MakeVectorDXDYDZ( 1.0, 0.1, 0.0, "xDir" )
+yDir = geompy.MakeVectorDXDYDZ(-0.1, 1.0, 0.0, "yDir" )
+zDir = geompy.MakeVectorDXDYDZ( 0.2, 0.3, 1.0, "zDir" )
+face = geompy.MakePrismVecH( xDir, yDir, 1.0 )
+box = geompy.MakePrismVecH( face, zDir, 1.0, theName="box" )
+
+spc = "0.1" # spacing
+
+# default axes
+mesh = smesh.Mesh( box, "custom axes")
+algo = mesh.BodyFitted()
+algo.SetGrid( spc, spc, spc, 10000 )
+mesh.Compute()
+print "Default axes"
+print " nb hex:",mesh.NbHexas()
+
+# set axes using edges of the box
+algo.SetAxesDirs( xDir, [-0.1,1,0], zDir )
+mesh.Compute()
+print "Manual axes"
+print " nb hex:",mesh.NbHexas()
+
+# set optimal orthogonal axes
+algo.SetOptimalAxesDirs( isOrthogonal=True )
+mesh.Compute()
+print "Optimal orthogonal axes"
+print " nb hex:",mesh.NbHexas()
+
+# set optimal non-orthogonal axes
+algo.SetOptimalAxesDirs( isOrthogonal=False )
+mesh.Compute()
+print "Optimal non-orthogonal axes"
+print " nb hex:",mesh.NbHexas()
diff --git a/doc/salome/gui/SMESH/images/cartesian3D_hyp.png b/doc/salome/gui/SMESH/images/cartesian3D_hyp.png
index b8373ed6d..c9a605fea 100644
Binary files a/doc/salome/gui/SMESH/images/cartesian3D_hyp.png and b/doc/salome/gui/SMESH/images/cartesian3D_hyp.png differ
diff --git a/doc/salome/gui/SMESH/images/cartesian_implement_edge.png b/doc/salome/gui/SMESH/images/cartesian_implement_edge.png
new file mode 100644
index 000000000..59ac9ba6f
Binary files /dev/null and b/doc/salome/gui/SMESH/images/cartesian_implement_edge.png differ
diff --git a/doc/salome/gui/SMESH/input/cartesian_algo.doc b/doc/salome/gui/SMESH/input/cartesian_algo.doc
index 3240150c7..dfb9acad4 100644
--- a/doc/salome/gui/SMESH/input/cartesian_algo.doc
+++ b/doc/salome/gui/SMESH/input/cartesian_algo.doc
@@ -31,7 +31,7 @@ nodes are inside and some outside.
To apply this algorithm when you define your mesh, select Body
Fitting in the list of 3D algorithms and click "Add
Hypothesis" button and "Body Fitting Parameters" " menu
- item. Dialog of Body Fitting Parameters
+item. Dialog of Body Fitting Parameters
hypothesis will appear.
@@ -42,34 +42,64 @@ To apply this algorithm when you define your mesh, select Body
This dialog allows to define
-\b Name of the algorithm
- Minimal size of a cell truncated by the geometry boundary. If the
- size of a truncated grid cell is \b Threshold times less than a
- initial cell size, then a mesh element is not created.
- Cartesian structured grid. Each grid axis is defined
- individually. Definition mode chooses a way of grid
- definition:
- You can specify the \b Coordinates of grid nodes. \b Insert button
- inserts a node at distance \b Step (negative or positive) from a
- selected node. \b Delete button removes a selected node. Double
- click on a coordinate in the list enables its edition. A grid
- defined by \b Coordinates should enclose the geometry, else the
- algorithm will fail.
- You can define the \b Spacing of a grid as an algebraic formula
- f(t) where \a t is a position along a grid axis
- normalized at [0.0,1.0]. The whole range of geometry can be
- divided into sub-ranges with their own spacing formulas to apply;
+ \b Name of the algorithm.
+ Minimal size of a cell truncated by the geometry boundary. If the
+ size of a truncated grid cell is \b Threshold times less than a
+ initial cell size, then a mesh element is not created.
+ Implement Edges check-box activates incorporation of
+ geometrical edges in the mesh.
+\image html cartesian_implement_edge.png "'Implement Edges' switched off (left) and on (right)"
+ Cartesian structured grid. Location of nodes along each grid axis
+ is defined individually. Definition mode chooses a way of
+ grid definition:
+
+ You can specify the \b Coordinates of grid nodes. \b Insert button
+ inserts a node at distance \b Step (negative or positive) from a
+ selected node. \b Delete button removes a selected node. Double
+ click on a coordinate in the list enables its edition.
+ \b Note that node coordinates are measured along directions of
+ axes that can differ from the directions of the Global Coordinate
+ System.
+ You can define the \b Spacing of a grid as an algebraic formula
+ f(t) where \a t is a position along a grid axis
+ normalized at [0.0,1.0]. The whole range of geometry can be
+ divided into sub-ranges with their own spacing formulas to apply;
\a t varies between 0.0 and 1.0 within each sub-range. \b Insert button
- divides a selected range into two ones. \b Delete button adds the
- selected sub-range to the previous one. Double click on a range in
- the list enables edition of its right boundary. Double click on a
- function in the list enables its edition.
-
-
+ divides a selected range into two ones. \b Delete button adds the
+ selected sub-range to the previous one. Double click on a range in
+ the list enables edition of its right boundary. Double click on a
+ function in the list enables its edition.
+
+
+ Coordinates of a Fixed Point . They allow to exactly
+ locate a grid node in a direction defined by spacing. If all the three
+ directions are defined by spacing, then there will be a mesh node at
+ the Fixed Point . If two directions are defined by spacing,
+ then there will be at least a link between mesh nodes passing through
+ the Fixed Point . If only one direction is defined by spacing,
+ then there will be at least an element facet passing through
+ the Fixed Point . If no directions are defined by spacing,
+ Fixed Point is disabled.
+ Directions of Axes . You can set up almost any
+ directions of grid axes that can help in generation as many as
+ possible hexahedral elements.
+
+ Orthogonal Axes check-box, if activated, keeps the
+ axes orthogonal during their modification.
+ Selection buttons enable snapping corresponding axes to
+ direction of a geometrical edge selected in the Object
+ Browser. Edge direction is defined by coordinates of its end
+ points.
+ Optimal Axes button runs an algorithm that tries to
+ set the axes so that a number of generated hexahedra to be
+ maximal.
+ Reset button returns the axes in a default position
+ parallel to the axes of the Global Coordinate System.
+
-See Also a sample TUI Script of a
-\ref tui_cartesian_algo "Usage of Body Fitting algorithm".
+See Also a sample TUI Script of a
+\ref tui_cartesian_algo "Usage of Body Fitting algorithm".
*/
diff --git a/idl/SMESH_BasicHypothesis.idl b/idl/SMESH_BasicHypothesis.idl
index 186b06681..27cfbd368 100644
--- a/idl/SMESH_BasicHypothesis.idl
+++ b/idl/SMESH_BasicHypothesis.idl
@@ -942,8 +942,9 @@ module StdMeshers
/*!
* interface of "Body fitting Parameters" hypothesis.
* This hypothesis specifies
- * - Definition of the Cartesian grid
* - Size threshold
+ * - Definition of the Cartesian grid
+ * - Direction of grid axes
*/
interface StdMeshers_CartesianParameters3D : SMESH::SMESH_Hypothesis
{
@@ -965,8 +966,8 @@ module StdMeshers
/*!
* Set coordinates of nodes along an axis (countered from zero)
*/
- void SetGrid(in SMESH::double_array coords,
- in short axis) raises (SALOME::SALOME_Exception);
+ void SetGrid(in SMESH::double_array coords,
+ in short axis) raises (SALOME::SALOME_Exception);
SMESH::double_array GetGrid(in short axis) raises (SALOME::SALOME_Exception);
/*!
@@ -985,6 +986,22 @@ module StdMeshers
void GetGridSpacing(out SMESH::string_array spaceFunctions,
out SMESH::double_array internalPoints,
in short axis) raises (SALOME::SALOME_Exception);
+ /*!
+ * Set custom direction of axes
+ */
+ void SetAxesDirs(in SMESH::DirStruct x,
+ in SMESH::DirStruct y,
+ in SMESH::DirStruct z ) raises (SALOME::SALOME_Exception);
+ void GetAxesDirs(out SMESH::DirStruct x,
+ out SMESH::DirStruct y,
+ out SMESH::DirStruct z );
+ /*!
+ * Set/unset a fixed point, at which a node will be created provided that grid
+ * is defined by spacing in all directions
+ */
+ void SetFixedPoint(in SMESH::PointStruct p, in boolean toUnset);
+ boolean GetFixedPoint(out SMESH::PointStruct p);
+
/*!
* Enables implementation of geometrical edges into the mesh. If this feature
* is disabled, sharp edges of the shape are lost ("smoothed") in the mesh if
@@ -993,6 +1010,16 @@ module StdMeshers
void SetToAddEdges(in boolean toAdd);
boolean GetToAddEdges();
+ /*!
+ * Returns axes at which a number of generated hexahedra is maximal
+ */
+ void ComputeOptimalAxesDirs(in GEOM::GEOM_Object shape,
+ in boolean isOrthogonal,
+ out SMESH::DirStruct x,
+ out SMESH::DirStruct y,
+ out SMESH::DirStruct z )
+ raises (SALOME::SALOME_Exception);
+
/*!
* \brief Computes node coordinates by spacing functions
* \param x0 - lower coordinate
diff --git a/src/SMESH_I/SMESH_2smeshpy.cxx b/src/SMESH_I/SMESH_2smeshpy.cxx
index 15e2a183f..b8358a795 100644
--- a/src/SMESH_I/SMESH_2smeshpy.cxx
+++ b/src/SMESH_I/SMESH_2smeshpy.cxx
@@ -2632,6 +2632,8 @@ Handle(_pyHypothesis) _pyHypothesis::NewHypothesis( const Handle(_pyCommand)& th
hyp->SetConvMethodAndType( "SetGrid", "Cartesian_3D");
for ( int iArg = 0; iArg < 4; ++iArg )
hyp->setCreationArg( iArg+1, "[]");
+ hyp->AddAccumulativeMethod( "SetGrid" );
+ hyp->AddAccumulativeMethod( "SetGridSpacing" );
}
else
{
@@ -3114,7 +3116,9 @@ void _pyComplexParamHypo::Process( const Handle(_pyCommand)& theCommand)
myCurCrMethod->myArgs[ iArg ] += "]";
}
myArgCommands.push_back( theCommand );
- rememberCmdOfParameter( theCommand );
+ //rememberCmdOfParameter( theCommand ); -- these commands are marked as
+ // accumulative, else, if the creation
+ // is not converted, commands for axes 1 and 2 are lost
return;
}
}
diff --git a/src/SMESH_SWIG/StdMeshersBuilder.py b/src/SMESH_SWIG/StdMeshersBuilder.py
index 4e5b2d217..265a9801b 100644
--- a/src/SMESH_SWIG/StdMeshersBuilder.py
+++ b/src/SMESH_SWIG/StdMeshersBuilder.py
@@ -597,7 +597,7 @@ class StdMeshersBuilder_Quadrangle(Mesh_Algorithm):
# must be created by the mesher. Shapes can be of any type,
# vertices of given shapes define positions of enforced nodes.
# Only vertices successfully projected to the face are used.
- # @param enfPoint: list of points giving positions of enforced nodes.
+ # @param enfPoints: list of points giving positions of enforced nodes.
# Point can be defined either as SMESH.PointStruct's
# ([SMESH.PointStruct(x1,y1,z1), SMESH.PointStruct(x2,y2,z2),...])
# or triples of values ([[x1,y1,z1], [x2,y2,z2], ...]).
@@ -1415,7 +1415,7 @@ class StdMeshersBuilder_Cartesian_3D(Mesh_Algorithm):
if not self.mesh.IsUsedHypothesis( self.hyp, self.geom ):
self.mesh.AddHypothesis( self.hyp, self.geom )
- for axis, gridDef in enumerate( [xGridDef, yGridDef, zGridDef]):
+ for axis, gridDef in enumerate( [xGridDef, yGridDef, zGridDef] ):
if not gridDef: raise ValueError, "Empty grid definition"
if isinstance( gridDef, str ):
self.hyp.SetGridSpacing( [gridDef], [], axis )
@@ -1429,6 +1429,64 @@ class StdMeshersBuilder_Cartesian_3D(Mesh_Algorithm):
self.hyp.SetSizeThreshold( sizeThreshold )
return self.hyp
+ ## Defines custom directions of axes of the grid
+ # @param xAxis either SMESH.DirStruct or a vector, or 3 vector components
+ # @param yAxis either SMESH.DirStruct or a vector, or 3 vector components
+ # @param zAxis either SMESH.DirStruct or a vector, or 3 vector components
+ def SetAxesDirs( self, xAxis, yAxis, zAxis ):
+ import GEOM
+ if hasattr( xAxis, "__getitem__" ):
+ xAxis = self.mesh.smeshpyD.MakeDirStruct( xAxis[0],xAxis[1],xAxis[2] )
+ elif isinstance( xAxis, GEOM._objref_GEOM_Object ):
+ xAxis = self.mesh.smeshpyD.GetDirStruct( xAxis )
+ if hasattr( yAxis, "__getitem__" ):
+ yAxis = self.mesh.smeshpyD.MakeDirStruct( yAxis[0],yAxis[1],yAxis[2] )
+ elif isinstance( yAxis, GEOM._objref_GEOM_Object ):
+ yAxis = self.mesh.smeshpyD.GetDirStruct( yAxis )
+ if hasattr( zAxis, "__getitem__" ):
+ zAxis = self.mesh.smeshpyD.MakeDirStruct( zAxis[0],zAxis[1],zAxis[2] )
+ elif isinstance( zAxis, GEOM._objref_GEOM_Object ):
+ zAxis = self.mesh.smeshpyD.GetDirStruct( zAxis )
+ if not self.hyp:
+ self.hyp = self.Hypothesis("CartesianParameters3D")
+ if not self.mesh.IsUsedHypothesis( self.hyp, self.geom ):
+ self.mesh.AddHypothesis( self.hyp, self.geom )
+ self.hyp.SetAxesDirs( xAxis, yAxis, zAxis )
+ return self.hyp
+
+ ## Automatically defines directions of axes of the grid at which
+ # a number of generated hexahedra is maximal
+ # @param isOrthogonal defines whether the axes mush be orthogonal
+ def SetOptimalAxesDirs(self, isOrthogonal=True):
+ if not self.hyp:
+ self.hyp = self.Hypothesis("CartesianParameters3D")
+ if not self.mesh.IsUsedHypothesis( self.hyp, self.geom ):
+ self.mesh.AddHypothesis( self.hyp, self.geom )
+ x,y,z = self.hyp.ComputeOptimalAxesDirs( self.geom, isOrthogonal )
+ self.hyp.SetAxesDirs( x,y,z )
+ return self.hyp
+
+ ## Sets/unsets a fixed point. The algorithm makes a plane of the grid pass
+ # through the fixed point in each direction at which the grid is defined
+ # by spacing
+ # @param p coordinates of the fixed point. Either SMESH.PointStruct or
+ # 3 components of coordinates.
+ # @param toUnset defines whether the fixed point is defined or removed.
+ def SetFixedPoint( self, p, toUnset=False ):
+ import SMESH
+ if toUnset:
+ if not self.hyp: return
+ p = SMESH.PointStruct(0,0,0)
+ if hasattr( p, "__getitem__" ):
+ p = SMESH.PointStruct( p[0],p[1],p[2] )
+ if not self.hyp:
+ self.hyp = self.Hypothesis("CartesianParameters3D")
+ if not self.mesh.IsUsedHypothesis( self.hyp, self.geom ):
+ self.mesh.AddHypothesis( self.hyp, self.geom )
+ self.hyp.SetFixedPoint( p, toUnset )
+ return self.hyp
+
+
pass # end of StdMeshersBuilder_Cartesian_3D class
## Defines a stub 1D algorithm, which enables "manual" creation of nodes and
diff --git a/src/StdMeshers/StdMeshers_CartesianParameters3D.cxx b/src/StdMeshers/StdMeshers_CartesianParameters3D.cxx
index 369d4e424..00cd8615e 100644
--- a/src/StdMeshers/StdMeshers_CartesianParameters3D.cxx
+++ b/src/StdMeshers/StdMeshers_CartesianParameters3D.cxx
@@ -32,10 +32,24 @@
#include "utilities.h"
+#include
#include
+#include
+#include
#include
+#include
+#include
+#include
#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
#include
using namespace std;
@@ -66,6 +80,11 @@ StdMeshers_CartesianParameters3D::StdMeshers_CartesianParameters3D(int h
_axisDirs[6] = 0.;
_axisDirs[7] = 0.;
_axisDirs[8] = 1.;
+
+ _fixedPoint[0] = 0.;
+ _fixedPoint[1] = 0.;
+ _fixedPoint[2] = 0.;
+ SetFixedPoint( _fixedPoint, /*toUnset=*/true );
}
@@ -73,6 +92,22 @@ namespace
{
const char* axisName[3] = { "X", "Y", "Z" };
+ typedef std::pair< double, std::pair< double, double > > TCooTriple;
+
+#define gpXYZ( cTriple ) gp_XYZ( (cTriple).first, (cTriple).second.first, (cTriple).second.second )
+
+ //================================================================================
+ /*!
+ * \brief Compare two normals
+ */
+ //================================================================================
+
+ bool sameDir( const TCooTriple& n1, const TCooTriple& n2 )
+ {
+ gp_XYZ xyz1 = gpXYZ( n1 ), xyz2 = gpXYZ( n2 );
+ return ( xyz1 - xyz2 ).Modulus() < 0.01;
+ }
+
//================================================================================
/*!
* \brief Checks validity of an axis index, throws in case of invalidity
@@ -177,6 +212,36 @@ void StdMeshers_CartesianParameters3D::SetGridSpacing(std::vector& xSpac
NotifySubMeshesHypothesisModification();
}
+//=======================================================================
+//function : SetFixedPoint
+//purpose : * Set/unset a fixed point, at which a node will be created provided that grid
+// * is defined by spacing in all directions
+//=======================================================================
+
+void StdMeshers_CartesianParameters3D::SetFixedPoint(const double p[3], bool toUnset)
+{
+ if ( toUnset != Precision::IsInfinite( _fixedPoint[0] ))
+ NotifySubMeshesHypothesisModification();
+
+ if ( toUnset )
+ _fixedPoint[0] = Precision::Infinite();
+ else
+ std::copy( &p[0], &p[0]+3, &_fixedPoint[0] );
+}
+
+//=======================================================================
+//function : GetFixedPoint
+//purpose : Returns either false or (true + point coordinates)
+//=======================================================================
+
+bool StdMeshers_CartesianParameters3D::GetFixedPoint(double p[3])
+{
+ if ( Precision::IsInfinite( _fixedPoint[0] ))
+ return false;
+ std::copy( &_fixedPoint[0], &_fixedPoint[0]+3, &p[0] );
+}
+
+
//=======================================================================
//function : SetSizeThreshold
//purpose : Set size threshold
@@ -322,9 +387,199 @@ void StdMeshers_CartesianParameters3D::GetCoordinates(std::vector& xNode
zNodes = _coords[2];
}
+//=======================================================================
+//function : ComputeOptimalAxesDirs
+//purpose : Returns axes at which number of hexahedra is maximal
+//=======================================================================
+
+void StdMeshers_CartesianParameters3D::
+ComputeOptimalAxesDirs(const TopoDS_Shape& shape,
+ const bool isOrthogonal,
+ double dirCoords[9])
+{
+ for ( int i = 0; i < 9; ++i ) dirCoords[i] = 0.;
+ dirCoords[0] = dirCoords[4] = dirCoords[8] = 1.;
+
+ if ( shape.IsNull() ) return;
+
+ TopLoc_Location loc;
+ TopExp_Explorer exp;
+
+ // get external FACEs of the shape
+ TopTools_MapOfShape faceMap;
+ for ( exp.Init( shape, TopAbs_FACE ); exp.More(); exp.Next() )
+ if ( !faceMap.Add( exp.Current() ))
+ faceMap.Remove( exp.Current() );
+
+ // sort areas of planar faces by normal direction
+
+ std::multimap< TCooTriple, double > areasByNormal;
+
+ TopTools_MapIteratorOfMapOfShape fIt ( faceMap );
+ for ( ; fIt.More(); fIt.Next() )
+ {
+ const TopoDS_Face& face = TopoDS::Face( fIt.Key() );
+ Handle(Geom_Surface) surf = BRep_Tool::Surface( face, loc );
+ if ( surf.IsNull() ) continue;
+
+ GeomLib_IsPlanarSurface check( surf, 1e-5 );
+ if ( !check.IsPlanar() ) continue;
+
+ GProp_GProps SProps;
+ BRepGProp::SurfaceProperties( face, SProps );
+ double area = SProps.Mass();
+
+ gp_Pln pln = check.Plan();
+ gp_Dir norm = pln.Axis().Direction().Transformed( loc );
+ if ( norm.X() < -1e-3 ) { // negative X
+ norm.Reverse();
+ } else if ( norm.X() < 1e-3 ) { // zero X
+ if ( norm.Y() < -1e-3 ) { // negative Y
+ norm.Reverse();
+ } else if ( norm.Y() < 1e-3 ) { // zero X && zero Y
+ if ( norm.Y() < -1e-3 ) // negative Z
+ norm.Reverse();
+ }
+ }
+ TCooTriple coo3( norm.X(), make_pair( norm.Y(), norm.Z() ));
+ areasByNormal.insert( make_pair( coo3, area ));
+ }
+
+ // group coplanar normals and sort groups by sum area
+
+ std::multimap< double, vector< const TCooTriple* > > normsByArea;
+ std::multimap< TCooTriple, double >::iterator norm2a = areasByNormal.begin();
+ const TCooTriple* norm1 = 0;
+ double sumArea = 0;
+ vector< const TCooTriple* > norms;
+ for ( int iF = 1; norm2a != areasByNormal.end(); ++norm2a, ++iF )
+ {
+
+ if ( !norm1 || !sameDir( *norm1, norm2a->first ))
+ {
+ if ( !norms.empty() )
+ {
+ normsByArea.insert( make_pair( sumArea, norms ));
+ norms.clear();
+ }
+ norm1 = & norm2a->first;
+ sumArea = norm2a->second;
+ norms.push_back( norm1 );
+ }
+ else
+ {
+ sumArea += norm2a->second;
+ norms.push_back( & norm2a->first );
+ }
+ if ( iF == areasByNormal.size() )
+ normsByArea.insert( make_pair( sumArea, norms ));
+ }
+
+ // try to set dirs by planar faces
+
+ gp_XYZ normDirs[3]; // normals to largest planes
+
+ if ( !normsByArea.empty() )
+ {
+ norm1 = normsByArea.rbegin()->second[0];
+ normDirs[0] = gpXYZ( *norm1 );
+
+ if ( normsByArea.size() == 1 )
+ {
+ normDirs[1] = normDirs[0];
+ if ( Abs( normDirs[0].Y() ) < 1e-100 &&
+ Abs( normDirs[0].Z() ) < 1e-100 ) // normDirs[0] || OX
+ normDirs[1].SetY( normDirs[0].Y() + 1. );
+ else
+ normDirs[1].SetX( normDirs[0].X() + 1. );
+ }
+ else
+ {
+ // look for 2 other directions
+ gp_XYZ testDir = normDirs[0], minDir, maxDir;
+ for ( int is2nd = 0; is2nd < 2; ++is2nd )
+ {
+ double maxMetric = 0, minMetric = 1e100;
+ std::multimap< double, vector< const TCooTriple* > >::iterator a2n;
+ for ( a2n = normsByArea.begin(); a2n != normsByArea.end(); ++a2n )
+ {
+ gp_XYZ n = gpXYZ( *( a2n->second[0]) );
+ double dot = Abs( n * testDir );
+ double metric = ( 1. - dot ) * ( isOrthogonal ? 1 : a2n->first );
+ if ( metric > maxMetric )
+ {
+ maxDir = n;
+ maxMetric = metric;
+ }
+ if ( metric < minMetric )
+ {
+ minDir = n;
+ minMetric = metric;
+ }
+ }
+ if ( is2nd )
+ {
+ normDirs[2] = minDir;
+ }
+ else
+ {
+ normDirs[1] = maxDir;
+ normDirs[2] = normDirs[0] ^ normDirs[1];
+ if ( isOrthogonal || normsByArea.size() < 3 )
+ break;
+ testDir = normDirs[2];
+ }
+ }
+ }
+ if ( isOrthogonal || normsByArea.size() == 1 )
+ {
+ normDirs[2] = normDirs[0] ^ normDirs[1];
+ normDirs[1] = normDirs[2] ^ normDirs[0];
+ }
+ }
+ else
+ {
+ return;
+ }
+
+ gp_XYZ dirs[3];
+ dirs[0] = normDirs[0] ^ normDirs[1];
+ dirs[1] = normDirs[1] ^ normDirs[2];
+ dirs[2] = normDirs[2] ^ normDirs[0];
+
+ dirs[0].Normalize();
+ dirs[1].Normalize();
+ dirs[2].Normalize();
+
+ // Select dirs for X, Y and Z axes
+ int iX = ( Abs( dirs[0].X() ) > Abs( dirs[1].X() )) ? 0 : 1;
+ if ( Abs( dirs[iX].X() ) < Abs( dirs[2].X() ))
+ iX = 2;
+ int iY = ( iX == 0 ) ? 1 : (( Abs( dirs[0].Y() ) > Abs( dirs[1].Y() )) ? 0 : 1 );
+ if ( Abs( dirs[iY].Y() ) < Abs( dirs[2].Y() ) && iX != 2 )
+ iY = 2;
+ int iZ = 3 - iX - iY;
+
+ if ( dirs[iX].X() < 0 ) dirs[iX].Reverse();
+ if ( dirs[iY].Y() < 0 ) dirs[iY].Reverse();
+ gp_XYZ zDir = dirs[iX] ^ dirs[iY];
+ if ( dirs[iZ] * zDir < 0 )
+ dirs[iZ].Reverse();
+
+ dirCoords[0] = dirs[iX].X();
+ dirCoords[1] = dirs[iX].Y();
+ dirCoords[2] = dirs[iX].Z();
+ dirCoords[3] = dirs[iY].X();
+ dirCoords[4] = dirs[iY].Y();
+ dirCoords[5] = dirs[iY].Z();
+ dirCoords[6] = dirs[iZ].X();
+ dirCoords[7] = dirs[iZ].Y();
+ dirCoords[8] = dirs[iZ].Z();
+}
+
//=======================================================================
//function : SetAxisDirs
-//purpose : Sets directions of axes
+//purpose : Sets custom direction of axes
//=======================================================================
void StdMeshers_CartesianParameters3D::SetAxisDirs(const double* the9DirComps)
@@ -349,6 +604,10 @@ void StdMeshers_CartesianParameters3D::SetAxisDirs(const double* the9DirComps)
y.IsParallel( z, M_PI / 180. ))
throw SALOME_Exception("Parallel axis directions");
+ gp_Vec normXY = x ^ y, normYZ = y ^ z;
+ if ( normXY.IsParallel( normYZ, M_PI / 180. ))
+ throw SALOME_Exception("Axes lie in one plane");
+
bool isChanged = false;
for ( int i = 0; i < 9; ++i )
{
@@ -450,6 +709,14 @@ std::ostream & StdMeshers_CartesianParameters3D::SaveTo(std::ostream & save)
}
save << _toAddEdges << " ";
+ save.setf( save.scientific );
+ save.precision( 12 );
+ for ( int i = 0; i < 9; ++i )
+ save << _axisDirs[i] << " ";
+
+ for ( int i = 0; i < 3; ++i )
+ save << _fixedPoint[i] << " ";
+
return save;
}
@@ -500,7 +767,13 @@ std::istream & StdMeshers_CartesianParameters3D::LoadFrom(std::istream & load)
}
}
- load >> _toAddEdges;
+ ok = ( load >> _toAddEdges );
+
+ for ( int i = 0; i < 9 && ok; ++i )
+ ok = ( load >> _axisDirs[i]);
+
+ for ( int i = 0; i < 3 && ok ; ++i )
+ ok = ( load >> _fixedPoint[i]);
return load;
}
diff --git a/src/StdMeshers/StdMeshers_CartesianParameters3D.hxx b/src/StdMeshers/StdMeshers_CartesianParameters3D.hxx
index 98970956b..3ef431cc9 100644
--- a/src/StdMeshers/StdMeshers_CartesianParameters3D.hxx
+++ b/src/StdMeshers/StdMeshers_CartesianParameters3D.hxx
@@ -78,6 +78,13 @@ public:
bool IsGridBySpacing(const int axis) const throw ( SALOME_Exception );
+ /*!
+ * Set/unset a fixed point, at which a node will be created provided that grid
+ * is defined by spacing in all directions
+ */
+ void SetFixedPoint(const double p[3], bool toUnset);
+ bool GetFixedPoint(double p[3]);
+
/*!
* \brief Computes node coordinates by spacing functions
* \param x0 - lower coordinate
@@ -101,13 +108,21 @@ public:
std::vector& zNodes,
const Bnd_Box& bndBox) const throw ( SALOME_Exception );
+ /*!
+ * \brief Set custom direction of axes
+ */
void SetAxisDirs(const double* the9DirComps) throw ( SALOME_Exception );
const double* GetAxisDirs() const { return _axisDirs; }
-
+ /*!
+ * \brief Returns axes at which number of hexahedra is maximal
+ */
+ static void ComputeOptimalAxesDirs(const TopoDS_Shape& shape,
+ const bool isOrthogonal,
+ double dirCoords[9]);
/*!
* Set size threshold. A polyhedral cell got by cutting an initial
* hexahedron by geometry boundary is considered small and is removed if
- * it's size is \athreshold times less than the size of the initial hexahedron.
+ * it's size is \athreshold times less than the size of the initial hexahedron.
*/
void SetSizeThreshold(const double threshold) throw ( SALOME_Exception );
/*!
@@ -150,7 +165,8 @@ public:
std::vector _spaceFunctions[3];
std::vector _internalPoints[3];
- double _axisDirs[9];
+ double _axisDirs [9];
+ double _fixedPoint[3];
double _sizeThreshold;
bool _toAddEdges;
diff --git a/src/StdMeshers/StdMeshers_Cartesian_3D.cxx b/src/StdMeshers/StdMeshers_Cartesian_3D.cxx
index 36b2e2d48..b8c4a92ff 100644
--- a/src/StdMeshers/StdMeshers_Cartesian_3D.cxx
+++ b/src/StdMeshers/StdMeshers_Cartesian_3D.cxx
@@ -37,12 +37,17 @@
#include
#include
+#include
+
#include
#include
#include
#include
+#include
#include
+#include
#include
+#include
#include
#include
#include
@@ -67,6 +72,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -218,12 +224,9 @@ namespace
*/
struct GridPlanes
{
- double _factor;
gp_XYZ _uNorm, _vNorm, _zNorm;
vector< gp_XYZ > _origins; // origin points of all planes in one direction
vector< double > _zProjs; // projections of origins to _zNorm
-
- gp_XY GetUV( const gp_Pnt& p, const gp_Pnt& origin );
};
// --------------------------------------------------------------------------
/*!
@@ -276,6 +279,9 @@ namespace
gp_XYZ _axes [3]; // axis directions
vector< GridLine > _lines [3]; // in 3 directions
double _tol, _minCellSize;
+ gp_XYZ _origin;
+ gp_Mat _invB; // inverted basis of _axes
+ //bool _isOrthogonalAxes;
vector< const SMDS_MeshNode* > _nodes; // mesh nodes at grid nodes
vector< const F_IntersectPoint* > _gridIntP; // grid node intersection with geometry
@@ -301,7 +307,8 @@ namespace
const vector& yCoords,
const vector& zCoords,
const double* axesDirs,
- const TopoDS_Shape& shape );
+ const Bnd_Box& bndBox );
+ void ComputeUVW(const gp_XYZ& p, double uvw[3]);
void ComputeNodes(SMESH_MesherHelper& helper);
};
#ifdef ELLIPSOLID_WORKAROUND
@@ -646,7 +653,7 @@ namespace
inline void locateValue( int & i, double val, const vector& values,
int& di, double tol )
{
- val += values[0]; // input \a val is measured from 0.
+ //val += values[0]; // input \a val is measured from 0.
if ( i > values.size()-2 )
i = values.size()-2;
else
@@ -721,16 +728,6 @@ namespace
return prevIsOut; // _transition == Trans_TANGENT
}
//================================================================================
- /*
- * Returns parameters of a point in i-th plane
- */
- gp_XY GridPlanes::GetUV( const gp_Pnt& p, const gp_Pnt& origin )
- {
- gp_Vec v( origin, p );
- return gp_XY( v.Dot( _uNorm ) * _factor,
- v.Dot( _vNorm ) * _factor );
- }
- //================================================================================
/*
* Adds face IDs
*/
@@ -793,11 +790,12 @@ namespace
const vector& yCoords,
const vector& zCoords,
const double* axesDirs,
- const TopoDS_Shape& shape)
+ const Bnd_Box& shapeBox)
{
_coords[0] = xCoords;
_coords[1] = yCoords;
_coords[2] = zCoords;
+
_axes[0].SetCoord( axesDirs[0],
axesDirs[1],
axesDirs[2]);
@@ -807,6 +805,16 @@ namespace
_axes[2].SetCoord( axesDirs[6],
axesDirs[7],
axesDirs[8]);
+ _axes[0].Normalize();
+ _axes[1].Normalize();
+ _axes[2].Normalize();
+
+ _invB.SetCols( _axes[0], _axes[1], _axes[2] );
+ _invB.Invert();
+
+ // _isOrthogonalAxes = ( Abs( _axes[0] * _axes[1] ) < 1e-20 &&
+ // Abs( _axes[1] * _axes[2] ) < 1e-20 &&
+ // Abs( _axes[2] * _axes[0] ) < 1e-20 );
// compute tolerance
_minCellSize = Precision::Infinite();
@@ -821,21 +829,37 @@ namespace
}
if ( _minCellSize < Precision::Confusion() )
throw SMESH_ComputeError (COMPERR_ALGO_FAILED,
- SMESH_Comment("Too small cell size: ") << _tol );
+ SMESH_Comment("Too small cell size: ") << _minCellSize );
_tol = _minCellSize / 1000.;
- // attune grid extremities to shape bounding box computed by vertices
- Bnd_Box shapeBox;
- for ( TopExp_Explorer vExp( shape, TopAbs_VERTEX ); vExp.More(); vExp.Next() )
- shapeBox.Add( BRep_Tool::Pnt( TopoDS::Vertex( vExp.Current() )));
-
+ // attune grid extremities to shape bounding box
+
double sP[6]; // aXmin, aYmin, aZmin, aXmax, aYmax, aZmax
shapeBox.Get(sP[0],sP[1],sP[2],sP[3],sP[4],sP[5]);
double* cP[6] = { &_coords[0].front(), &_coords[1].front(), &_coords[2].front(),
&_coords[0].back(), &_coords[1].back(), &_coords[2].back() };
for ( int i = 0; i < 6; ++i )
if ( fabs( sP[i] - *cP[i] ) < _tol )
- *cP[i] = sP[i] + _tol/1000. * ( i < 3 ? +1 : -1 );
+ *cP[i] = sP[i];// + _tol/1000. * ( i < 3 ? +1 : -1 );
+
+ for ( int iDir = 0; iDir < 3; ++iDir )
+ {
+ if ( _coords[iDir][0] - sP[iDir] > _tol )
+ {
+ _minCellSize = Min( _minCellSize, _coords[iDir][0] - sP[iDir] );
+ _coords[iDir].insert( _coords[iDir].begin(), sP[iDir] + _tol/1000.);
+ }
+ if ( sP[iDir+3] - _coords[iDir].back() > _tol )
+ {
+ _minCellSize = Min( _minCellSize, sP[iDir+3] - _coords[iDir].back() );
+ _coords[iDir].push_back( sP[iDir+3] - _tol/1000.);
+ }
+ }
+ _tol = _minCellSize / 1000.;
+
+ _origin = ( _coords[0][0] * _axes[0] +
+ _coords[1][0] * _axes[1] +
+ _coords[2][0] * _axes[2] );
// create lines
for ( int iDir = 0; iDir < 3; ++iDir ) // loop on 3 line directions
@@ -843,17 +867,34 @@ namespace
LineIndexer li = GetLineIndexer( iDir );
_lines[iDir].resize( li.NbLines() );
double len = _coords[ iDir ].back() - _coords[iDir].front();
- gp_Vec dir( iDir==0, iDir==1, iDir==2 );
for ( ; li.More(); ++li )
{
GridLine& gl = _lines[iDir][ li.LineIndex() ];
- gl._line.SetLocation(gp_Pnt(_coords[0][li.I()], _coords[1][li.J()], _coords[2][li.K()]));
- gl._line.SetDirection( dir );
+ gl._line.SetLocation( _coords[0][li.I()] * _axes[0] +
+ _coords[1][li.J()] * _axes[1] +
+ _coords[2][li.K()] * _axes[2] );
+ gl._line.SetDirection( _axes[ iDir ]);
gl._length = len;
}
}
}
//================================================================================
+ /*
+ * Computes coordinates of a point in the grid CS
+ */
+ void Grid::ComputeUVW(const gp_XYZ& P, double UVW[3])
+ {
+ // gp_XYZ p = P - _origin;
+ // UVW[ 0 ] = p.X() * _invB( 1, 1 ) + p.Y() * _invB( 1, 2 ) + p.Z() * _invB( 1, 3 );
+ // UVW[ 1 ] = p.X() * _invB( 2, 1 ) + p.Y() * _invB( 2, 2 ) + p.Z() * _invB( 2, 3 );
+ // UVW[ 2 ] = p.X() * _invB( 3, 1 ) + p.Y() * _invB( 3, 2 ) + p.Z() * _invB( 3, 3 );
+ // UVW[ 0 ] += _coords[0][0];
+ // UVW[ 1 ] += _coords[1][0];
+ // UVW[ 2 ] += _coords[2][0];
+ gp_XYZ p = P * _invB;
+ p.Coord( UVW[0], UVW[1], UVW[2] );
+ }
+ //================================================================================
/*
* Creates all nodes
*/
@@ -882,12 +923,16 @@ namespace
nIndex0 = NodeIndex( li.I(), li.J(), li.K() );
GridLine& line = _lines[ iDir ][ li.LineIndex() ];
+ const gp_XYZ lineLoc = line._line.Location().XYZ();
+ const gp_XYZ lineDir = line._line.Direction().XYZ();
line.RemoveExcessIntPoints( _tol );
multiset< F_IntersectPoint >& intPnts = _lines[ iDir ][ li.LineIndex() ]._intPoints;
multiset< F_IntersectPoint >::iterator ip = intPnts.begin();
bool isOut = true;
- const double* nodeCoord = & coords[0], *coord0 = nodeCoord, *coordEnd = coord0 + coords.size();
+ const double* nodeCoord = & coords[0];
+ const double* coord0 = nodeCoord;
+ const double* coordEnd = coord0 + coords.size();
double nodeParam = 0;
for ( ; ip != intPnts.end(); ++ip )
{
@@ -910,10 +955,11 @@ namespace
// create a mesh node on a GridLine at ip if it does not coincide with a grid node
if ( nodeParam > ip->_paramOnLine + _tol )
{
- li.SetIndexOnLine( 0 );
- double xyz[3] = { _coords[0][ li.I() ], _coords[1][ li.J() ], _coords[2][ li.K() ]};
- xyz[ li._iConst ] += ip->_paramOnLine;
- ip->_node = helper.AddNode( xyz[0], xyz[1], xyz[2] );
+ // li.SetIndexOnLine( 0 );
+ // double xyz[3] = { _coords[0][ li.I() ], _coords[1][ li.J() ], _coords[2][ li.K() ]};
+ // xyz[ li._iConst ] += ip->_paramOnLine;
+ gp_XYZ xyz = lineLoc + ip->_paramOnLine * lineDir;
+ ip->_node = helper.AddNode( xyz.X(), xyz.Y(), xyz.Z() );
ip->_indexOnLine = nodeCoord-coord0-1;
}
// create a mesh node at ip concident with a grid node
@@ -922,9 +968,10 @@ namespace
int nodeIndex = nIndex0 + nShift * ( nodeCoord-coord0 );
if ( !_nodes[ nodeIndex ] )
{
- li.SetIndexOnLine( nodeCoord-coord0 );
- double xyz[3] = { _coords[0][ li.I() ], _coords[1][ li.J() ], _coords[2][ li.K() ]};
- _nodes [ nodeIndex ] = helper.AddNode( xyz[0], xyz[1], xyz[2] );
+ //li.SetIndexOnLine( nodeCoord-coord0 );
+ //double xyz[3] = { _coords[0][ li.I() ], _coords[1][ li.J() ], _coords[2][ li.K() ]};
+ gp_XYZ xyz = lineLoc + nodeParam * lineDir;
+ _nodes [ nodeIndex ] = helper.AddNode( xyz.X(), xyz.Y(), xyz.Z() );
_gridIntP[ nodeIndex ] = & * ip;
}
if ( _gridIntP[ nodeIndex ] )
@@ -951,7 +998,13 @@ namespace
{
size_t nodeIndex = NodeIndex( x, y, z );
if ( !isNodeOut[ nodeIndex ] && !_nodes[ nodeIndex] )
- _nodes[ nodeIndex ] = helper.AddNode( _coords[0][x], _coords[1][y], _coords[2][z] );
+ {
+ //_nodes[ nodeIndex ] = helper.AddNode( _coords[0][x], _coords[1][y], _coords[2][z] );
+ gp_XYZ xyz = ( _coords[0][x] * _axes[0] +
+ _coords[1][y] * _axes[1] +
+ _coords[2][z] * _axes[2] );
+ _nodes[ nodeIndex ] = helper.AddNode( xyz.X(), xyz.Y(), xyz.Z() );
+ }
}
#ifdef _MY_DEBUG_
@@ -1000,72 +1053,72 @@ namespace
*/
bool FaceGridIntersector::IsInGrid(const Bnd_Box& gridBox)
{
- double x0,y0,z0, x1,y1,z1;
- const Bnd_Box& faceBox = GetFaceBndBox();
- faceBox.Get(x0,y0,z0, x1,y1,z1);
+ // double x0,y0,z0, x1,y1,z1;
+ // const Bnd_Box& faceBox = GetFaceBndBox();
+ // faceBox.Get(x0,y0,z0, x1,y1,z1);
- if ( !gridBox.IsOut( gp_Pnt( x0,y0,z0 )) &&
- !gridBox.IsOut( gp_Pnt( x1,y1,z1 )))
- return true;
+ // if ( !gridBox.IsOut( gp_Pnt( x0,y0,z0 )) &&
+ // !gridBox.IsOut( gp_Pnt( x1,y1,z1 )))
+ // return true;
- double X0,Y0,Z0, X1,Y1,Z1;
- gridBox.Get(X0,Y0,Z0, X1,Y1,Z1);
- double faceP[6] = { x0,y0,z0, x1,y1,z1 };
- double gridP[6] = { X0,Y0,Z0, X1,Y1,Z1 };
- gp_Dir axes[3] = { gp::DX(), gp::DY(), gp::DZ() };
- for ( int iDir = 0; iDir < 6; ++iDir )
- {
- if ( iDir < 3 && gridP[ iDir ] <= faceP[ iDir ] ) continue;
- if ( iDir >= 3 && gridP[ iDir ] >= faceP[ iDir ] ) continue;
+ // double X0,Y0,Z0, X1,Y1,Z1;
+ // gridBox.Get(X0,Y0,Z0, X1,Y1,Z1);
+ // double faceP[6] = { x0,y0,z0, x1,y1,z1 };
+ // double gridP[6] = { X0,Y0,Z0, X1,Y1,Z1 };
+ // gp_Dir axes[3] = { gp::DX(), gp::DY(), gp::DZ() };
+ // for ( int iDir = 0; iDir < 6; ++iDir )
+ // {
+ // if ( iDir < 3 && gridP[ iDir ] <= faceP[ iDir ] ) continue;
+ // if ( iDir >= 3 && gridP[ iDir ] >= faceP[ iDir ] ) continue;
- // check if the face intersects a side of a gridBox
+ // // check if the face intersects a side of a gridBox
- gp_Pnt p = iDir < 3 ? gp_Pnt( X0,Y0,Z0 ) : gp_Pnt( X1,Y1,Z1 );
- gp_Ax1 norm( p, axes[ iDir % 3 ] );
- if ( iDir < 3 ) norm.Reverse();
+ // gp_Pnt p = iDir < 3 ? gp_Pnt( X0,Y0,Z0 ) : gp_Pnt( X1,Y1,Z1 );
+ // gp_Ax1 norm( p, axes[ iDir % 3 ] );
+ // if ( iDir < 3 ) norm.Reverse();
- gp_XYZ O = norm.Location().XYZ(), N = norm.Direction().XYZ();
+ // gp_XYZ O = norm.Location().XYZ(), N = norm.Direction().XYZ();
- TopLoc_Location loc = _face.Location();
- Handle(Poly_Triangulation) aPoly = BRep_Tool::Triangulation(_face,loc);
- if ( !aPoly.IsNull() )
- {
- if ( !loc.IsIdentity() )
- {
- norm.Transform( loc.Transformation().Inverted() );
- O = norm.Location().XYZ(), N = norm.Direction().XYZ();
- }
- const double deflection = aPoly->Deflection();
+ // TopLoc_Location loc = _face.Location();
+ // Handle(Poly_Triangulation) aPoly = BRep_Tool::Triangulation(_face,loc);
+ // if ( !aPoly.IsNull() )
+ // {
+ // if ( !loc.IsIdentity() )
+ // {
+ // norm.Transform( loc.Transformation().Inverted() );
+ // O = norm.Location().XYZ(), N = norm.Direction().XYZ();
+ // }
+ // const double deflection = aPoly->Deflection();
- const TColgp_Array1OfPnt& nodes = aPoly->Nodes();
- for ( int i = nodes.Lower(); i <= nodes.Upper(); ++i )
- if (( nodes( i ).XYZ() - O ) * N > _grid->_tol + deflection )
- return false;
- }
- else
- {
- BRepAdaptor_Surface surf( _face );
- double u0, u1, v0, v1, du, dv, u, v;
- BRepTools::UVBounds( _face, u0, u1, v0, v1);
- if ( surf.GetType() == GeomAbs_Plane ) {
- du = u1 - u0, dv = v1 - v0;
- }
- else {
- du = surf.UResolution( _grid->_minCellSize / 10. );
- dv = surf.VResolution( _grid->_minCellSize / 10. );
- }
- for ( u = u0, v = v0; u <= u1 && v <= v1; u += du, v += dv )
- {
- gp_Pnt p = surf.Value( u, v );
- if (( p.XYZ() - O ) * N > _grid->_tol )
- {
- TopAbs_State state = GetCurveFaceIntersector()->ClassifyUVPoint(gp_Pnt2d( u, v ));
- if ( state == TopAbs_IN || state == TopAbs_ON )
- return false;
- }
- }
- }
- }
+ // const TColgp_Array1OfPnt& nodes = aPoly->Nodes();
+ // for ( int i = nodes.Lower(); i <= nodes.Upper(); ++i )
+ // if (( nodes( i ).XYZ() - O ) * N > _grid->_tol + deflection )
+ // return false;
+ // }
+ // else
+ // {
+ // BRepAdaptor_Surface surf( _face );
+ // double u0, u1, v0, v1, du, dv, u, v;
+ // BRepTools::UVBounds( _face, u0, u1, v0, v1);
+ // if ( surf.GetType() == GeomAbs_Plane ) {
+ // du = u1 - u0, dv = v1 - v0;
+ // }
+ // else {
+ // du = surf.UResolution( _grid->_minCellSize / 10. );
+ // dv = surf.VResolution( _grid->_minCellSize / 10. );
+ // }
+ // for ( u = u0, v = v0; u <= u1 && v <= v1; u += du, v += dv )
+ // {
+ // gp_Pnt p = surf.Value( u, v );
+ // if (( p.XYZ() - O ) * N > _grid->_tol )
+ // {
+ // TopAbs_State state = GetCurveFaceIntersector()->ClassifyUVPoint(gp_Pnt2d( u, v ));
+ // if ( state == TopAbs_IN || state == TopAbs_ON )
+ // return false;
+ // }
+ // }
+ // }
+ // }
return true;
}
//=============================================================================
@@ -1139,7 +1192,7 @@ namespace
if ( _bndBox.IsOut( gridLine._line )) continue;
intersector._intPoints.clear();
- (intersector.*interFunction)( gridLine );
+ (intersector.*interFunction)( gridLine ); // <- intersection with gridLine
for ( size_t i = 0; i < intersector._intPoints.size(); ++i )
_intersections.push_back( make_pair( &gridLine, intersector._intPoints[i] ));
}
@@ -1188,7 +1241,7 @@ namespace
*/
void FaceLineIntersector::IntersectWithCylinder(const GridLine& gridLine)
{
- IntAna_IntConicQuad linCylinder( gridLine._line,_cylinder);
+ IntAna_IntConicQuad linCylinder( gridLine._line, _cylinder );
if ( linCylinder.IsDone() && linCylinder.NbPoints() > 0 )
{
_w = linCylinder.ParamOnConic(1);
@@ -1644,6 +1697,23 @@ namespace
} // loop on _edgeIntPnts
}
+ else if ( 3 < _nbCornerNodes && _nbCornerNodes < 8 ) // _nbIntNodes == 0
+ {
+ _Link split;
+ // create sub-links (_splits) of whole links
+ for ( int iLink = 0; iLink < 12; ++iLink )
+ {
+ _Link& link = _hexLinks[ iLink ];
+ link._splits.clear();
+ if ( link._nodes[ 0 ]->Node() && link._nodes[ 1 ]->Node() )
+ {
+ split._nodes[ 0 ] = link._nodes[0];
+ split._nodes[ 1 ] = link._nodes[1];
+ link._splits.push_back( split );
+ }
+ }
+ }
+
}
//================================================================================
/*!
@@ -1877,8 +1947,8 @@ namespace
{
curLink = freeLinks[ iL ];
freeLinks[ iL ] = 0;
- polygon._links.push_back( *curLink );
--nbFreeLinks;
+ polygon._links.push_back( *curLink );
}
} while ( curLink );
}
@@ -1983,16 +2053,23 @@ namespace
} // if there are intersections with EDGEs
- if ( polygon._links.size() < 3 ||
+ if ( polygon._links.size() < 2 ||
polygon._links[0].LastNode() != polygon._links.back().FirstNode() )
return; // closed polygon not found -> invalid polyhedron
- // add polygon to its links
- for ( size_t iL = 0; iL < polygon._links.size(); ++iL )
+ if ( polygon._links.size() == 2 )
{
- polygon._links[ iL ]._link->_faces.reserve( 2 );
- polygon._links[ iL ]._link->_faces.push_back( &polygon );
- polygon._links[ iL ].Reverse();
+ _polygons.pop_back();
+ }
+ else
+ {
+ // add polygon to its links
+ for ( size_t iL = 0; iL < polygon._links.size(); ++iL )
+ {
+ polygon._links[ iL ]._link->_faces.reserve( 2 );
+ polygon._links[ iL ]._link->_faces.push_back( &polygon );
+ polygon._links[ iL ].Reverse();
+ }
}
} // while ( nbFreeLinks > 0 )
@@ -2096,12 +2173,12 @@ namespace
if ( hex )
{
intHexInd[ nbIntHex++ ] = i;
- if ( hex->_nbIntNodes > 0 ) continue;
- init( hex->_i, hex->_j, hex->_k );
+ if ( hex->_nbIntNodes > 0 ) continue; // treat intersected hex later
+ this->init( hex->_i, hex->_j, hex->_k );
}
else
{
- init( i );
+ this->init( i );
}
if ( _nbCornerNodes == 8 && ( _nbBndNodes < _nbCornerNodes || !isInHole() ))
{
@@ -2124,7 +2201,10 @@ namespace
{
// all intersection of hex with geometry are at grid nodes
hex = new Hexahedron( *this );
- hex->init( i );
+ //hex->init( i );
+ hex->_i = _i;
+ hex->_j = _j;
+ hex->_k = _k;
intHexInd.push_back(0);
intHexInd[ nbIntHex++ ] = i;
}
@@ -2168,39 +2248,27 @@ namespace
// Prepare planes for intersecting with EDGEs
GridPlanes pln[3];
{
- gp_XYZ origPnt = ( _grid->_coords[0][0] * _grid->_axes[0] +
- _grid->_coords[1][0] * _grid->_axes[1] +
- _grid->_coords[2][0] * _grid->_axes[2] );
for ( int iDirZ = 0; iDirZ < 3; ++iDirZ ) // iDirZ gives normal direction to planes
{
GridPlanes& planes = pln[ iDirZ ];
int iDirX = ( iDirZ + 1 ) % 3;
int iDirY = ( iDirZ + 2 ) % 3;
- planes._uNorm = ( _grid->_axes[ iDirY ] ^ _grid->_axes[ iDirZ ] ).Normalized();
- planes._vNorm = ( _grid->_axes[ iDirZ ] ^ _grid->_axes[ iDirX ] ).Normalized();
+ // planes._uNorm = ( _grid->_axes[ iDirY ] ^ _grid->_axes[ iDirZ ] ).Normalized();
+ // planes._vNorm = ( _grid->_axes[ iDirZ ] ^ _grid->_axes[ iDirX ] ).Normalized();
planes._zNorm = ( _grid->_axes[ iDirX ] ^ _grid->_axes[ iDirY ] ).Normalized();
- double uvDot = planes._uNorm * planes._vNorm;
- planes._factor = sqrt( 1. - uvDot * uvDot );
- planes._origins.resize( _grid->_coords[ iDirZ ].size() );
planes._zProjs.resize ( _grid->_coords[ iDirZ ].size() );
- planes._origins[0] = origPnt;
planes._zProjs [0] = 0;
const double zFactor = _grid->_axes[ iDirZ ] * planes._zNorm;
const vector< double > & u = _grid->_coords[ iDirZ ];
- for ( int i = 1; i < planes._origins.size(); ++i )
+ for ( int i = 1; i < planes._zProjs.size(); ++i )
{
- planes._origins[i] = origPnt + _grid->_axes[ iDirZ ] * ( u[i] - u[0] );
planes._zProjs [i] = zFactor * ( u[i] - u[0] );
}
}
}
const double deflection = _grid->_minCellSize / 20.;
const double tol = _grid->_tol;
- // int facets[6] = { SMESH_Block::ID_F0yz, SMESH_Block::ID_F1yz,
- // SMESH_Block::ID_Fx0z, SMESH_Block::ID_Fx1z,
- // SMESH_Block::ID_Fxy0, SMESH_Block::ID_Fxy1 };
E_IntersectPoint ip;
- //ip._faceIDs.reserve(2);
// Intersect EDGEs with the planes
map< TGeomID, vector< TGeomID > >::const_iterator e2fIt = edge2faceIDsMap.begin();
@@ -2209,6 +2277,8 @@ namespace
const TGeomID edgeID = e2fIt->first;
const TopoDS_Edge & E = TopoDS::Edge( _grid->_shapes( edgeID ));
BRepAdaptor_Curve curve( E );
+ TopoDS_Vertex v1 = helper.IthVertex( 0, E, false );
+ TopoDS_Vertex v2 = helper.IthVertex( 1, E, false );
ip._faceIDs = e2fIt->second;
ip._shapeID = edgeID;
@@ -2226,34 +2296,34 @@ namespace
int iDirY = ( iDirZ + 2 ) % 3;
double xLen = _grid->_coords[ iDirX ].back() - _grid->_coords[ iDirX ][0];
double yLen = _grid->_coords[ iDirY ].back() - _grid->_coords[ iDirY ][0];
- double zFactor = _grid->_axes[ iDirZ ] * planes._zNorm;
+ double zLen = _grid->_coords[ iDirZ ].back() - _grid->_coords[ iDirZ ][0];
+ //double zFactor = _grid->_axes[ iDirZ ] * planes._zNorm;
int dIJK[3], d000[3] = { 0,0,0 };
+ double o[3] = { _grid->_coords[0][0],
+ _grid->_coords[1][0],
+ _grid->_coords[2][0] };
// locate the 1st point of a segment within the grid
gp_XYZ p1 = discret.Value( 1 ).XYZ();
double u1 = discret.Parameter( 1 );
- double zProj1 = planes._zNorm * ( p1 - planes._origins[0] );
- gp_Pnt orig = planes._origins[0] + planes._zNorm * zProj1;
- gp_XY uv = planes.GetUV( p1, orig );
- int iX1 = int( uv.X() / xLen * ( _grid->_coords[ iDirX ].size() - 1. ));
- int iY1 = int( uv.Y() / yLen * ( _grid->_coords[ iDirY ].size() - 1. ));
- int iZ1 = int( zProj1 / planes._zProjs.back() * ( planes._zProjs.size() - 1. ));
- locateValue( iX1, uv.X(), _grid->_coords[ iDirX ], dIJK[ iDirX ], tol );
- locateValue( iY1, uv.Y(), _grid->_coords[ iDirY ], dIJK[ iDirY ], tol );
- locateValue( iZ1, zProj1, planes._zProjs , dIJK[ iDirZ ], tol );
+ double zProj1 = planes._zNorm * ( p1 - _grid->_origin );
+
+ _grid->ComputeUVW( p1, ip._uvw );
+ int iX1 = int(( ip._uvw[iDirX] - o[iDirX]) / xLen * (_grid->_coords[ iDirX ].size() - 1));
+ int iY1 = int(( ip._uvw[iDirY] - o[iDirY]) / yLen * (_grid->_coords[ iDirY ].size() - 1));
+ int iZ1 = int(( ip._uvw[iDirZ] - o[iDirZ]) / zLen * (_grid->_coords[ iDirZ ].size() - 1));
+ locateValue( iX1, ip._uvw[iDirX], _grid->_coords[ iDirX ], dIJK[ iDirX ], tol );
+ locateValue( iY1, ip._uvw[iDirY], _grid->_coords[ iDirY ], dIJK[ iDirY ], tol );
+ locateValue( iZ1, ip._uvw[iDirZ], _grid->_coords[ iDirZ ], dIJK[ iDirZ ], tol );
int ijk[3]; // grid index where a segment intersect a plane
ijk[ iDirX ] = iX1;
ijk[ iDirY ] = iY1;
ijk[ iDirZ ] = iZ1;
- ip._uvw[ iDirX ] = uv.X() + _grid->_coords[ iDirX ][0];
- ip._uvw[ iDirY ] = uv.Y() + _grid->_coords[ iDirY ][0];
- ip._uvw[ iDirZ ] = zProj1 / zFactor + _grid->_coords[ iDirZ ][0];
// add the 1st vertex point to a hexahedron
if ( iDirZ == 0 )
{
- //ip._shapeID = _grid->_shapes.Add( helper.IthVertex( 0, curve.Edge(),/*CumOri=*/false));
ip._point = p1;
_grid->_edgeIntP.push_back( ip );
if ( !addIntersection( _grid->_edgeIntP.back(), hexes, ijk, d000 ))
@@ -2264,7 +2334,7 @@ namespace
// locate the 2nd point of a segment within the grid
gp_XYZ p2 = discret.Value( iP ).XYZ();
double u2 = discret.Parameter( iP );
- double zProj2 = planes._zNorm * ( p2 - planes._origins[0] );
+ double zProj2 = planes._zNorm * ( p2 - _grid->_origin );
int iZ2 = iZ1;
locateValue( iZ2, zProj2, planes._zProjs, dIJK[ iDirZ ], tol );
@@ -2275,14 +2345,11 @@ namespace
{
ip._point = findIntPoint( u1, zProj1, u2, zProj2,
planes._zProjs[ iZ ],
- curve, planes._zNorm, planes._origins[0] );
- gp_XY uv = planes.GetUV( ip._point, planes._origins[ iZ ]);
- locateValue( ijk[ iDirX ], uv.X(), _grid->_coords[ iDirX ], dIJK[ iDirX ], tol );
- locateValue( ijk[ iDirY ], uv.Y(), _grid->_coords[ iDirY ], dIJK[ iDirY ], tol );
+ curve, planes._zNorm, _grid->_origin );
+ _grid->ComputeUVW( ip._point.XYZ(), ip._uvw );
+ locateValue( ijk[iDirX], ip._uvw[iDirX], _grid->_coords[iDirX], dIJK[iDirX], tol );
+ locateValue( ijk[iDirY], ip._uvw[iDirY], _grid->_coords[iDirY], dIJK[iDirY], tol );
ijk[ iDirZ ] = iZ;
- ip._uvw[ iDirX ] = uv.X() + _grid->_coords[ iDirX ][0];
- ip._uvw[ iDirY ] = uv.Y() + _grid->_coords[ iDirY ][0];
- ip._uvw[ iDirZ ] = planes._zProjs[ iZ ] / zFactor + _grid->_coords[ iDirZ ][0];
// add ip to hex "above" the plane
_grid->_edgeIntP.push_back( ip );
@@ -2303,15 +2370,11 @@ namespace
// add the 2nd vertex point to a hexahedron
if ( iDirZ == 0 )
{
- orig = planes._origins[0] + planes._zNorm * zProj1;
- uv = planes.GetUV( p1, orig );
- locateValue( ijk[ iDirX ], uv.X(), _grid->_coords[ iDirX ], dIJK[ iDirX ], tol );
- locateValue( ijk[ iDirY ], uv.Y(), _grid->_coords[ iDirY ], dIJK[ iDirY ], tol );
- ijk[ iDirZ ] = iZ1;
- ip._uvw[ iDirX ] = uv.X() + _grid->_coords[ iDirX ][0];
- ip._uvw[ iDirY ] = uv.Y() + _grid->_coords[ iDirY ][0];
- ip._uvw[ iDirZ ] = zProj1 / zFactor + _grid->_coords[ iDirZ ][0];
ip._point = p1;
+ _grid->ComputeUVW( p1, ip._uvw );
+ locateValue( ijk[iDirX], ip._uvw[iDirX], _grid->_coords[iDirX], dIJK[iDirX], tol );
+ locateValue( ijk[iDirY], ip._uvw[iDirY], _grid->_coords[iDirY], dIJK[iDirY], tol );
+ ijk[ iDirZ ] = iZ1;
_grid->_edgeIntP.push_back( ip );
if ( !addIntersection( _grid->_edgeIntP.back(), hexes, ijk, d000 ))
_grid->_edgeIntP.pop_back();
@@ -2356,8 +2419,6 @@ namespace
* \param [in] origin - the plane origin
* \return gp_Pnt - the found intersection point
*/
- //================================================================================
-
gp_Pnt Hexahedron::findIntPoint( double u1, double proj1,
double u2, double proj2,
double proj,
@@ -2381,7 +2442,7 @@ namespace
//================================================================================
/*!
- * \brief Returns index of a hexahedron sub-entities holding a point
+ * \brief Returns indices of a hexahedron sub-entities holding a point
* \param [in] ip - intersection point
* \param [out] facets - 0-3 facets holding a point
* \param [out] sub - index of a vertex or an edge holding a point
@@ -2466,7 +2527,7 @@ namespace
};
for ( int i = 0; i < 4; ++i )
{
- if ( 0 <= hexIndex[i] && hexIndex[i] < hexes.size() && hexes[ hexIndex[i] ] )
+ if ( /*0 <= hexIndex[i] &&*/ hexIndex[i] < hexes.size() && hexes[ hexIndex[i] ] )
{
Hexahedron* h = hexes[ hexIndex[i] ];
// check if ip is really inside the hex
@@ -2789,6 +2850,90 @@ namespace
return false;
}
+ //================================================================================
+ /*!
+ * \brief computes exact bounding box with axes parallel to given ones
+ */
+ //================================================================================
+
+ void getExactBndBox( const vector< TopoDS_Shape >& faceVec,
+ const double* axesDirs,
+ Bnd_Box& shapeBox )
+ {
+ BRep_Builder b;
+ TopoDS_Compound allFacesComp;
+ b.MakeCompound( allFacesComp );
+ for ( size_t iF = 0; iF < faceVec.size(); ++iF )
+ b.Add( allFacesComp, faceVec[ iF ] );
+
+ double sP[6]; // aXmin, aYmin, aZmin, aXmax, aYmax, aZmax
+ shapeBox.Get(sP[0],sP[1],sP[2],sP[3],sP[4],sP[5]);
+ double farDist = 0;
+ for ( int i = 0; i < 6; ++i )
+ farDist = Max( farDist, 10 * sP[i] );
+
+ gp_XYZ axis[3] = { gp_XYZ( axesDirs[0], axesDirs[1], axesDirs[2] ),
+ gp_XYZ( axesDirs[3], axesDirs[4], axesDirs[5] ),
+ gp_XYZ( axesDirs[6], axesDirs[7], axesDirs[8] ) };
+ axis[0].Normalize();
+ axis[1].Normalize();
+ axis[2].Normalize();
+
+ gp_Mat basis( axis[0], axis[1], axis[2] );
+ gp_Mat bi = basis.Inverted();
+
+ gp_Pnt pMin, pMax;
+ for ( int iDir = 0; iDir < 3; ++iDir )
+ {
+ gp_XYZ axis0 = axis[ iDir ];
+ gp_XYZ axis1 = axis[ ( iDir + 1 ) % 3 ];
+ gp_XYZ axis2 = axis[ ( iDir + 2 ) % 3 ];
+ for ( int isMax = 0; isMax < 2; ++isMax )
+ {
+ double shift = isMax ? farDist : -farDist;
+ gp_XYZ orig = shift * axis0;
+ gp_XYZ norm = axis1 ^ axis2;
+ gp_Pln pln( orig, norm );
+ norm = pln.Axis().Direction().XYZ();
+ BRepBuilderAPI_MakeFace plane( pln, -farDist, farDist, -farDist, farDist );
+
+ gp_Pnt& pAxis = isMax ? pMax : pMin;
+ gp_Pnt pPlane, pFaces;
+ double dist = GEOMUtils::GetMinDistance( plane, allFacesComp, pPlane, pFaces );
+ if ( dist < 0 )
+ {
+ Bnd_B3d bb;
+ gp_XYZ corner;
+ for ( int i = 0; i < 2; ++i ) {
+ corner.SetCoord( 1, sP[ i*3 ]);
+ for ( int j = 0; j < 2; ++j ) {
+ corner.SetCoord( 2, sP[ i*3 + 1 ]);
+ for ( int k = 0; k < 2; ++k )
+ {
+ corner.SetCoord( 3, sP[ i*3 + 2 ]);
+ corner *= bi;
+ bb.Add( corner );
+ }
+ }
+ }
+ corner = isMax ? bb.CornerMax() : bb.CornerMin();
+ pAxis.SetCoord( iDir+1, corner.Coord( iDir+1 ));
+ }
+ else
+ {
+ gp_XYZ pf = pFaces.XYZ() * bi;
+ pAxis.SetCoord( iDir+1, pf.Coord( iDir+1 ) );
+ }
+ }
+ } // loop on 3 axes
+
+ shapeBox.SetVoid();
+ shapeBox.Add( pMin );
+ shapeBox.Add( pMax );
+
+ return;
+ }
+
} // namespace
//=============================================================================
@@ -2826,14 +2971,19 @@ bool StdMeshers_Cartesian_3D::Compute(SMESH_Mesh & theMesh,
vector< TopoDS_Shape > faceVec;
{
TopTools_MapOfShape faceMap;
- for ( TopExp_Explorer fExp( theShape, TopAbs_FACE ); fExp.More(); fExp.Next() )
- if ( faceMap.Add( fExp.Current() )) // skip a face shared by two solids
+ TopExp_Explorer fExp;
+ for ( fExp.Init( theShape, TopAbs_FACE ); fExp.More(); fExp.Next() )
+ if ( !faceMap.Add( fExp.Current() ))
+ faceMap.Remove( fExp.Current() ); // remove a face shared by two solids
+
+ for ( fExp.ReInit(); fExp.More(); fExp.Next() )
+ if ( faceMap.Contains( fExp.Current() ))
faceVec.push_back( fExp.Current() );
}
- Bnd_Box shapeBox;
vector facesItersectors( faceVec.size() );
map< TGeomID, vector< TGeomID > > edge2faceIDsMap;
TopExp_Explorer eExp;
+ Bnd_Box shapeBox;
for ( int i = 0; i < faceVec.size(); ++i )
{
facesItersectors[i]._face = TopoDS::Face ( faceVec[i] );
@@ -2850,32 +3000,13 @@ bool StdMeshers_Cartesian_3D::Compute(SMESH_Mesh & theMesh,
}
}
+ getExactBndBox( faceVec, _hyp->GetAxisDirs(), shapeBox );
+
vector xCoords, yCoords, zCoords;
_hyp->GetCoordinates( xCoords, yCoords, zCoords, shapeBox );
- grid.SetCoordinates( xCoords, yCoords, zCoords, _hyp->GetAxisDirs(), theShape );
+ grid.SetCoordinates( xCoords, yCoords, zCoords, _hyp->GetAxisDirs(), shapeBox );
- // check if the grid encloses the shape
- if ( !_hyp->IsGridBySpacing(0) ||
- !_hyp->IsGridBySpacing(1) ||
- !_hyp->IsGridBySpacing(2) )
- {
- Bnd_Box gridBox;
- gridBox.Add( gp_Pnt( xCoords[0], yCoords[0], zCoords[0] ));
- gridBox.Add( gp_Pnt( xCoords.back(), yCoords.back(), zCoords.back() ));
- double x0,y0,z0, x1,y1,z1;
- shapeBox.Get(x0,y0,z0, x1,y1,z1);
- if ( gridBox.IsOut( gp_Pnt( x0,y0,z0 )) ||
- gridBox.IsOut( gp_Pnt( x1,y1,z1 )))
- for ( size_t i = 0; i < facesItersectors.size(); ++i )
- {
- if ( !facesItersectors[i].IsInGrid( gridBox ))
- return error("The grid doesn't enclose the geometry");
-#ifdef ELLIPSOLID_WORKAROUND
- delete facesItersectors[i]._surfaceInt, facesItersectors[i]._surfaceInt = 0;
-#endif
- }
- }
if ( _computeCanceled ) return false;
#ifdef WITH_TBB
diff --git a/src/StdMeshersGUI/StdMeshersGUI_CartesianParamCreator.cxx b/src/StdMeshersGUI/StdMeshersGUI_CartesianParamCreator.cxx
index c2b58de8d..be926470e 100644
--- a/src/StdMeshersGUI/StdMeshersGUI_CartesianParamCreator.cxx
+++ b/src/StdMeshersGUI/StdMeshersGUI_CartesianParamCreator.cxx
@@ -25,18 +25,33 @@
// SMESH includes
#include "StdMeshersGUI_CartesianParamCreator.h"
-#include
-#include
-#include
-#include
+#include "SMESHGUI.h"
+#include "SMESHGUI_Utils.h"
+#include "SMESHGUI_VTKUtils.h"
+#include "SMESHGUI_HypothesesUtils.h"
+#include "SMESHGUI_SpinBox.h"
+#include "SMESHGUI_MeshEditPreview.h"
// IDL includes
#include CORBA_SERVER_HEADER(SMESH_BasicHypothesis)
// SALOME GUI includes
-#include
-#include
+#include
#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+#include
// Qt includes
#include
@@ -201,11 +216,18 @@ namespace StdMeshersGUI
connect( myInsertBtn, SIGNAL( clicked() ), SLOT( onInsert() ));
connect( myDeleteBtn, SIGNAL( clicked() ), SLOT( onDelete() ));
connect( myModeGroup, SIGNAL( buttonClicked ( int )), SLOT( onMode(int)));
+ connect( myModeGroup, SIGNAL( buttonClicked ( int )), SIGNAL( gridModeChanged(int)));
connect( mySpacingTreeWdg, SIGNAL( itemSelectionChanged()), SLOT( updateButtons() ));
connect( myCoordList, SIGNAL( itemSelectionChanged()), SLOT( updateButtons() ));
connect( myStepSpin, SIGNAL( valueChanged(double)), SLOT( onStepChange() ));
}
+ //================================================================================
+ /*!
+ * \brief SLOT onInsert
+ */
+ //================================================================================
+
void GridAxisTab::onInsert()
{
if ( isGridBySpacing() )
@@ -254,6 +276,12 @@ namespace StdMeshersGUI
updateButtons();
}
+ //================================================================================
+ /*!
+ * \brief SLOT onDelete
+ */
+ //================================================================================
+
void GridAxisTab::onDelete()
{
if ( isGridBySpacing() )
@@ -283,6 +311,12 @@ namespace StdMeshersGUI
updateButtons();
}
+ //================================================================================
+ /*!
+ * \brief SLOT onMode
+ */
+ //================================================================================
+
void GridAxisTab::onMode(int isSpacing)
{
mySpacingTreeWdg->setShown( isSpacing );
@@ -313,6 +347,12 @@ namespace StdMeshersGUI
updateButtons();
}
+ //================================================================================
+ /*!
+ * \brief SLOT onStepChange
+ */
+ //================================================================================
+
void GridAxisTab::onStepChange()
{
if ( fabs( myStepSpin->GetValue() ) < 1e-100 )
@@ -323,6 +363,12 @@ namespace StdMeshersGUI
myStep = myStepSpin->GetValue();
}
+ //================================================================================
+ /*!
+ * \brief Enables/disables buttons
+ */
+ //================================================================================
+
void GridAxisTab::updateButtons()
{
bool insertEnable = false, deleteEnable = false;
@@ -347,6 +393,12 @@ namespace StdMeshersGUI
myDeleteBtn->setEnabled( deleteEnable );
}
+ //================================================================================
+ /*!
+ * \brief Inserts coordinates into myCoordList
+ */
+ //================================================================================
+
void GridAxisTab::setCoordinates( SMESH::double_array_var coords )
{
myCoordList->clear();
@@ -357,6 +409,12 @@ namespace StdMeshersGUI
onMode( COORD_BUT );
}
+ //================================================================================
+ /*!
+ * \brief Sets spacing got from hypothesis
+ */
+ //================================================================================
+
void GridAxisTab::setSpacing( SMESH::string_array_var funs, SMESH::double_array_var points )
{
mySpacingTreeWdg->clear();
@@ -370,11 +428,23 @@ namespace StdMeshersGUI
onMode( SPACING_BUT );
}
+ //================================================================================
+ /*!
+ * \brief Checks grid definintion mode
+ */
+ //================================================================================
+
bool GridAxisTab::isGridBySpacing() const
{
return ( myModeGroup->checkedId() == SPACING_BUT );
}
+ //================================================================================
+ /*!
+ * \brief Returns coordinates to set to a hypothesis
+ */
+ //================================================================================
+
SMESH::double_array* GridAxisTab::getCoordinates()
{
SMESH::double_array_var coords = new SMESH::double_array;
@@ -385,6 +455,12 @@ namespace StdMeshersGUI
return coords._retn();
}
+ //================================================================================
+ /*!
+ * \brief Returms spacing to set to a hypothesis
+ */
+ //================================================================================
+
void GridAxisTab::getSpacing(SMESH::string_array_out funs,
SMESH::double_array_out points) const
{
@@ -404,6 +480,12 @@ namespace StdMeshersGUI
}
+ //================================================================================
+ /*!
+ * \brief Verifies parameters
+ */
+ //================================================================================
+
bool GridAxisTab::checkParams(QString& msg, SMESH::SMESH_Hypothesis_var& hyp) const
{
if ( isGridBySpacing() )
@@ -432,6 +514,12 @@ namespace StdMeshersGUI
return true;
}
+ //================================================================================
+ /*!
+ * \brief LineDelegate constructor
+ */
+ //================================================================================
+
LineDelegate::LineDelegate( QWidget* parent ):
QItemDelegate( parent ),
mySpacingTreeWdg( qobject_cast( parent )),
@@ -439,6 +527,12 @@ namespace StdMeshersGUI
{
}
+ //================================================================================
+ /*!
+ * \brief Creates an editor depending on a current item
+ */
+ //================================================================================
+
QWidget* LineDelegate::createEditor( QWidget* parent,
const QStyleOptionViewItem& opt,
const QModelIndex& index) const
@@ -472,6 +566,12 @@ namespace StdMeshersGUI
return w;
}
+ //================================================================================
+ /*!
+ * \brief Limit value range in the spin of a neighbor range
+ */
+ //================================================================================
+
void LineDelegate::setEditorData ( QWidget * editor, const QModelIndex & index ) const
{
if ( mySpacingTreeWdg && index.column() == 0 )
@@ -494,6 +594,13 @@ namespace StdMeshersGUI
QItemDelegate::setEditorData( editor, index );
}
}
+
+ //================================================================================
+ /*!
+ * \brief
+ */
+ //================================================================================
+
void LineDelegate::setModelData( QWidget* editor,
QAbstractItemModel* model,
const QModelIndex& index ) const
@@ -530,6 +637,53 @@ namespace StdMeshersGUI
} // namespace StdMeshersGUI
+namespace
+{
+ const double theAngTol = M_PI / 180.;
+
+ //================================================================================
+ /*!
+ * \brief Set variables to groups of spin boxes
+ */
+ //================================================================================
+
+ void setText( const QString& vars, SMESHGUI_SpinBox** spins )
+ {
+ QStringList varList = vars.split( ':' );
+ for ( int i = 0; i < 3 && i < varList.count(); ++i )
+ if ( !varList[i].isEmpty() )
+ spins[i]->setText( varList[i] );
+ }
+
+ //================================================================================
+ /*!
+ * \brief Computes more 2 axes by one
+ * \param [in] iOk - index of a given axis
+ * \param [in,out] dirs - directions of 3 axes
+ */
+ //================================================================================
+
+ void get3Dirs( int iOk, gp_XYZ dirs[3] )
+ {
+ dirs[ ( iOk+1 ) % 3 ] = dirs[ iOk ];
+
+ if ( Abs( dirs[ iOk ].Y() ) < 1e-100 &&
+ Abs( dirs[ iOk ].Z() ) < 1e-100 )
+ // dirs[ iOk ] || OX
+ dirs[ ( iOk+1 ) % 3 ].SetY( dirs[ iOk ].Y() + 1. );
+ else
+ dirs[ ( iOk+1 ) % 3 ].SetX( dirs[ iOk ].X() + 1. );
+
+ dirs[( iOk+2 ) % 3] = dirs[ iOk ] ^ dirs[ ( iOk+1 ) % 3 ];
+ dirs[( iOk+1 ) % 3] = dirs[ ( iOk+2 ) % 3 ] ^ dirs[ iOk ];
+ }
+}
+
+//================================================================================
+/*!
+ * \brief StdMeshersGUI_CartesianParamCreator constructor
+ */
+//================================================================================
StdMeshersGUI_CartesianParamCreator::StdMeshersGUI_CartesianParamCreator(const QString& aHypType)
: StdMeshersGUI_StdHypothesisCreator( aHypType ),
@@ -538,8 +692,23 @@ StdMeshersGUI_CartesianParamCreator::StdMeshersGUI_CartesianParamCreator(const Q
myAxisTabs[0] = 0;
myAxisTabs[1] = 0;
myAxisTabs[2] = 0;
+
+ myAxesPreview = new SMESHGUI_MeshEditPreview( SMESH::GetViewWindow( SMESHGUI::GetSMESHGUI() ));
+ myAxesPreview->SetArrowShapeAndNb( /*nbArrows=*/3,
+ /*headLength=*/0.1,
+ /*headRadius=*/0.01,
+ /*start=*/0.,
+ /*labels=*/"XYZ");
+
+ myDirTic[0] = myDirTic[1] = myDirTic[2] = 0;
}
+//================================================================================
+/*!
+ * \brief StdMeshersGUI_CartesianParamCreator destructor
+ */
+//================================================================================
+
StdMeshersGUI_CartesianParamCreator::~StdMeshersGUI_CartesianParamCreator()
{
if ( myAxisTabs[0] ) delete myAxisTabs[0];
@@ -548,8 +717,16 @@ StdMeshersGUI_CartesianParamCreator::~StdMeshersGUI_CartesianParamCreator()
myAxisTabs[0] = 0;
myAxisTabs[1] = 0;
myAxisTabs[2] = 0;
+
+ delete myAxesPreview;
}
+//================================================================================
+/*!
+ * \brief Validate parameters
+ */
+//================================================================================
+
bool StdMeshersGUI_CartesianParamCreator::checkParams( QString& msg ) const
{
if( !SMESHGUI_GenericHypothesisCreator::checkParams( msg ) )
@@ -568,9 +745,22 @@ bool StdMeshersGUI_CartesianParamCreator::checkParams( QString& msg ) const
if ( !myAxisTabs[1]->checkParams( msg, hyp )) return false;
if ( !myAxisTabs[2]->checkParams( msg, hyp )) return false;
+ StdMeshersGUI_CartesianParamCreator* me = (StdMeshersGUI_CartesianParamCreator*) this;
+ if ( !me->updateAxesPreview() )
+ {
+ msg = tr("INVALID_AXES_DIR");
+ return false;
+ }
+
return true;
}
+//================================================================================
+/*!
+ * \brief Create widgets
+ */
+//================================================================================
+
QFrame* StdMeshersGUI_CartesianParamCreator::buildFrame()
{
QFrame* fr = new QFrame();
@@ -625,10 +815,154 @@ QFrame* StdMeshersGUI_CartesianParamCreator::buildFrame()
tabWdg->addTab( myAxisTabs[ 1 ], tr( "AXIS_Y" ) );
tabWdg->addTab( myAxisTabs[ 2 ], tr( "AXIS_Z" ) );
argGroupLayout->addWidget( tabWdg, row, 0, 1, 2 );
+ row++;
+
+ QPixmap aPix = SMESHGUI::resourceMgr()->loadPixmap("SMESH", tr("ICON_SELECT"));
+
+ // 4) Fixed point
+ myFixedPointGrp = new QGroupBox( tr("FIXED_POINT"), fr );
+ myFixedPointGrp->setCheckable( true );
+ //QPushButton* pointBtn = new QPushButton( QIcon(aPix), "", myFixedPointGrp );
+ QLabel* pXLbl = new QLabel( tr("SMESH_X"), myFixedPointGrp );
+ QLabel* pYLbl = new QLabel( tr("SMESH_Y"), myFixedPointGrp );
+ QLabel* pZLbl = new QLabel( tr("SMESH_Z"), myFixedPointGrp );
+ for ( int i = 0; i < 3; ++i )
+ {
+ myPointSpin[i] = new SMESHGUI_SpinBox( myFixedPointGrp );
+ myPointSpin[i]->RangeStepAndValidator( -1e20, 1e20, 10 );
+ myPointSpin[i]->SetValue( 0. );
+ }
+ QHBoxLayout* aFixedPointLay = new QHBoxLayout( myFixedPointGrp );
+ aFixedPointLay->addWidget( pXLbl, 0, Qt::AlignRight );
+ aFixedPointLay->addWidget( myPointSpin[0], 1 );
+ aFixedPointLay->addWidget( pYLbl, 0, Qt::AlignRight );
+ aFixedPointLay->addWidget( myPointSpin[1], 1 );
+ aFixedPointLay->addWidget( pZLbl, 0, Qt::AlignRight );
+ aFixedPointLay->addWidget( myPointSpin[2], 1 );
+ argGroupLayout->addWidget( myFixedPointGrp, row, 0, 1, 2 );
+ row++;
+
+ // 5) Axes direction
+ QGroupBox* axesDirGrp = new QGroupBox( tr("AXES_DIRECTION"), fr );
+ QGridLayout* axisDirLay = new QGridLayout( axesDirGrp );
+ axisDirLay->setSpacing( SPACING );
+ axisDirLay->setMargin( MARGIN );
+ axisDirLay->setColumnStretch( 0, 2 );
+ // is orthogonal
+ myOrthogonalChk = new QCheckBox( tr("ORTHOGONAL_AXES"), axesDirGrp );
+ axisDirLay->addWidget( myOrthogonalChk, 0, 0, 1, 7 );
+ // axes
+ QLabel* axisLbl[3];
+ axisLbl[0] = new QLabel( tr( "AXIS_X"), axesDirGrp );
+ axisLbl[1] = new QLabel( tr( "AXIS_Y"), axesDirGrp );
+ axisLbl[2] = new QLabel( tr( "AXIS_Z"), axesDirGrp );
+ QLabel* dLbl[3];
+ myAxisBtnGrp = new QButtonGroup( axesDirGrp );
+ SMESHGUI_SpinBox** spins[3] = { &myXDirSpin[0], &myYDirSpin[0], &myZDirSpin[0] };
+ for ( int i = 0; i < 3; ++i )
+ {
+ QPushButton* axisBtn = new QPushButton( QIcon(aPix), "", axesDirGrp );
+ axisBtn->setCheckable( true );
+ myAxisBtnGrp->addButton( axisBtn, i );
+ myXDirSpin[i] = new SMESHGUI_SpinBox( axesDirGrp );
+ myYDirSpin[i] = new SMESHGUI_SpinBox( axesDirGrp );
+ myZDirSpin[i] = new SMESHGUI_SpinBox( axesDirGrp );
+ myXDirSpin[i]->RangeStepAndValidator( -1, 1, 0.1, "len_tol_precision" );
+ myYDirSpin[i]->RangeStepAndValidator( -1, 1, 0.1, "len_tol_precision" );
+ myZDirSpin[i]->RangeStepAndValidator( -1, 1, 0.1, "len_tol_precision" );
+ dLbl[0] = new QLabel( tr("SMESH_DX"), axesDirGrp );
+ dLbl[1] = new QLabel( tr("SMESH_DY"), axesDirGrp );
+ dLbl[2] = new QLabel( tr("SMESH_DZ"), axesDirGrp );
+ axisDirLay->addWidget( axisLbl[i], i+1, 0 );
+ axisDirLay->addWidget( axisBtn, i+1, 1 );
+ axisDirLay->addWidget( dLbl[0], i+1, 2 );
+ axisDirLay->addWidget( dLbl[1], i+1, 4 );
+ axisDirLay->addWidget( dLbl[2], i+1, 6 );
+ axisDirLay->addWidget( myXDirSpin[i], 1, 3+i*2 );
+ axisDirLay->addWidget( myYDirSpin[i], 2, 3+i*2 );
+ axisDirLay->addWidget( myZDirSpin[i], 3, 3+i*2 );
+ }
+ axisDirLay->setColumnStretch( 3, 10 );
+ axisDirLay->setColumnStretch( 5, 10 );
+ axisDirLay->setColumnStretch( 7, 10 );
+
+ // set optimal axes
+ QPushButton* optimBtn = new QPushButton( tr("OPTIMAL_AXES"), axesDirGrp );
+ QPushButton* resetBtn = new QPushButton( tr("RESET_AXES"), axesDirGrp );
+ axisDirLay->addWidget( optimBtn, 4, 0, 1, 4 );
+ axisDirLay->addWidget( resetBtn, 4, 4, 1, 4 );
+
+ argGroupLayout->addWidget( axesDirGrp, row, 0, 1, 2 );
+ row++;
+
+ // Signals
+
+ LightApp_SelectionMgr* selMgr = SMESH::GetSelectionMgr( SMESHGUI::GetSMESHGUI() );
+
+ connect( selMgr, SIGNAL( currentSelectionChanged()), SLOT( onSelectionChange()));
+ connect( myOrthogonalChk, SIGNAL( toggled(bool)), SLOT( onOrthogonalAxes(bool)));
+ connect( optimBtn, SIGNAL( clicked(bool)), SLOT( onOptimalAxes(bool)));
+ connect( resetBtn, SIGNAL( clicked(bool)), SLOT( onResetAxes(bool)));
+ for ( int i = 0; i < 3; ++i )
+ {
+ connect( myXDirSpin[i], SIGNAL(valueChanged (const QString&)),
+ this, SLOT (onAxisDirChange(const QString&)) );
+ connect( myYDirSpin[i], SIGNAL(valueChanged (const QString&)),
+ this, SLOT (onAxisDirChange(const QString&)) );
+ connect( myZDirSpin[i], SIGNAL(valueChanged (const QString&)),
+ this, SLOT (onAxisDirChange(const QString&)) );
+ connect( myAxisTabs[i], SIGNAL(gridModeChanged(int)),
+ this, SLOT (onGridModeChanged(int)));
+ }
+
+ // Show axes
+ myAxesLen = 1;
+ myOrigin[0] = myOrigin[1] = myOrigin[2] = 0.;
+ TopoDS_Shape shape;
+ QString shapeEntry = getMainShapeEntry();
+ if ( !shapeEntry.isEmpty() )
+ {
+ // find origin
+ Handle(SALOME_InteractiveObject) io =
+ new SALOME_InteractiveObject( shapeEntry.toStdString().c_str(), "GEOM" );
+ GEOM::GEOM_Object_var geomObj = SMESH::IObjectToInterface( io );
+ if ( GEOMBase::GetShape( geomObj, shape ) && !shape.IsNull())
+ {
+ Bnd_Box box;
+ BRepBndLib::Add( shape, box );
+ double max[3];
+ if ( !box.IsVoid() )
+ {
+ box.Get( myOrigin[0], myOrigin[1], myOrigin[2], max[0], max[1], max[2] );
+ gp_Pnt o( myOrigin[0], myOrigin[1], myOrigin[2] );
+ gp_Pnt x( max[0], max[1], max[2] );
+ myAxesLen = o.Distance( x );
+
+ double step = 1e20;
+ while ( step > myAxesLen / 5 )
+ step /= 10;
+ myPointSpin[0]->SetStep( step );
+ myPointSpin[1]->SetStep( step );
+ myPointSpin[2]->SetStep( step );
+ }
+ }
+ }
+ myAxisBtnGrp->button(0)->setEnabled( !shape.IsNull() );
+ myAxisBtnGrp->button(1)->setEnabled( !shape.IsNull() );
+ myAxisBtnGrp->button(2)->setEnabled( !shape.IsNull() );
+ optimBtn->setEnabled( !shape.IsNull() );
+
+ updateAxesPreview();
return fr;
}
+//================================================================================
+/*!
+ * \brief Tranfer parameters from hypothesis to widgets
+ */
+//================================================================================
+
void StdMeshersGUI_CartesianParamCreator::retrieveParams() const
{
StdMeshers::StdMeshers_CartesianParameters3D_var h =
@@ -645,6 +979,7 @@ void StdMeshersGUI_CartesianParamCreator::retrieveParams() const
myAddEdges->setChecked( h->GetToAddEdges() );
+ // grid definition
for ( int ax = 0; ax < 3; ++ax )
{
if ( h->IsGridBySpacing( ax ))
@@ -660,11 +995,62 @@ void StdMeshersGUI_CartesianParamCreator::retrieveParams() const
myAxisTabs[ax]->setCoordinates( coords );
}
}
+
+ // fixed point
+ SMESH::PointStruct fp;
+ StdMeshersGUI_CartesianParamCreator* me = (StdMeshersGUI_CartesianParamCreator*) this;
+ if ( h->GetFixedPoint( fp ))
+ {
+ me->myPointSpin[0]->SetValue( fp.x );
+ me->myPointSpin[1]->SetValue( fp.y );
+ me->myPointSpin[2]->SetValue( fp.z );
+ setText( getVariableName("GetFixedPoint"), &me->myPointSpin[0] );
+ myFixedPointGrp->setChecked( true );
+ }
+ else
+ {
+ myFixedPointGrp->setChecked( false );
+ }
+
+ // axes directions
+ SMESHGUI_SpinBox** spins[3] = { &me->myXDirSpin[0], &me->myYDirSpin[0], &me->myZDirSpin[0] };
+ SMESH::DirStruct axisDir[3];
+ h->GetAxesDirs( axisDir[0],
+ axisDir[1],
+ axisDir[2]);
+ QString vars = getVariableName("GetAxesDirs");
+ for ( int i = 0; i < 3; ++i )
+ {
+ spins[i][0]->SetValue( axisDir[i].PS.x );
+ spins[i][1]->SetValue( axisDir[i].PS.y );
+ spins[i][2]->SetValue( axisDir[i].PS.z );
+ setText( vars, spins[i] );
+
+ // cut off 3 used vars
+ if ( !vars.isEmpty() )
+ {
+ int ind = -1;
+ for ( int j = 0; j < 3; ++j )
+ if (( ind = vars.indexOf(':', ind+1 )) < 0 )
+ break;
+ if ( ind < 0 )
+ vars.clear();
+ else
+ vars.remove( 0, ind+1 );
+ }
+ }
+
if ( dlg() )
dlg()->setMinimumSize( dlg()->minimumSizeHint().width(),
dlg()->minimumSizeHint().height() );
}
+//================================================================================
+/*!
+ * \brief Tranfer parameters from widgets to hypothesis
+ */
+//================================================================================
+
QString StdMeshersGUI_CartesianParamCreator::storeParams() const
{
StdMeshers::StdMeshers_CartesianParameters3D_var h =
@@ -675,10 +1061,12 @@ QString StdMeshersGUI_CartesianParamCreator::storeParams() const
if( isCreation() )
SMESH::SetName( SMESH::FindSObject( h ), myName->text().toLatin1().constData() );
+ // threshold
h->SetVarParameter( myThreshold->text().toLatin1().constData(), "SetSizeThreshold" );
h->SetSizeThreshold( myThreshold->text().toDouble() );
h->SetToAddEdges( myAddEdges->isChecked() );
+ // grid
for ( int ax = 0; ax < 3; ++ax )
{
if ( myAxisTabs[ax]->isGridBySpacing())
@@ -694,6 +1082,40 @@ QString StdMeshersGUI_CartesianParamCreator::storeParams() const
h->SetGrid( coords, ax );
}
}
+
+ // fixed point
+ QStringList params;
+ params << myPointSpin[0]->text();
+ params << myPointSpin[1]->text();
+ params << myPointSpin[2]->text();
+ h->SetVarParameter( params.join(":").toLatin1().constData(), "SetFixedPoint" );
+ params.clear();
+
+ SMESH::PointStruct ps;
+ ps.x = myPointSpin[0]->GetValue();
+ ps.y = myPointSpin[1]->GetValue();
+ ps.z = myPointSpin[2]->GetValue();
+ h->SetFixedPoint( ps, !myFixedPointGrp->isEnabled() || !myFixedPointGrp->isChecked() );
+
+ // axes directions
+ SMESHGUI_SpinBox* const * spins[3] = { &myXDirSpin[0], &myYDirSpin[0], &myZDirSpin[0] };
+ for ( int ax = 0; ax < 3; ++ax )
+ {
+ params << spins[ax][0]->text();
+ params << spins[ax][1]->text();
+ params << spins[ax][2]->text();
+ }
+ h->SetVarParameter( params.join(":").toLatin1().constData(), "SetAxesDirs" );
+
+ SMESH::DirStruct axDir[3];
+ for ( int ax = 0; ax < 3; ++ax )
+ {
+ axDir[ax].PS.x = spins[ax][0]->GetValue();
+ axDir[ax].PS.y = spins[ax][1]->GetValue();
+ axDir[ax].PS.z = spins[ax][2]->GetValue();
+ }
+ h->SetAxesDirs( axDir[0], axDir[1], axDir[2] );
+
}
catch(const SALOME::SALOME_Exception& ex)
{
@@ -702,7 +1124,298 @@ QString StdMeshersGUI_CartesianParamCreator::storeParams() const
return "";
}
+//================================================================================
+/*!
+ * \brief Returns a name of help page
+ */
+//================================================================================
+
QString StdMeshersGUI_CartesianParamCreator::helpPage() const
{
return "cartesian_algo_page.html#cartesian_hyp_anchor";
}
+
+//================================================================================
+/*!
+ * \brief Show axes if they are OK
+ */
+//================================================================================
+
+bool StdMeshersGUI_CartesianParamCreator::updateAxesPreview()
+{
+ bool isOk = true;
+ gp_Ax1 axes[3];
+ SMESHGUI_SpinBox** spins[3] = { &myXDirSpin[0], &myYDirSpin[0], &myZDirSpin[0] };
+ for ( int i = 0; i < 3 && isOk; ++i )
+ {
+ gp_XYZ dir( spins[i][0]->GetValue(),
+ spins[i][1]->GetValue(),
+ spins[i][2]->GetValue());
+ if (( isOk = ( dir.Modulus() > 1e-100 )))
+ axes[i].SetDirection( gp_Dir( dir ));
+
+ axes[i].SetLocation ( gp_Pnt( myOrigin[0],
+ myOrigin[1],
+ myOrigin[2]));
+ }
+ gp_Vec norm01 = axes[0].Direction().XYZ() ^ axes[1].Direction().XYZ();
+ gp_Vec norm12 = axes[1].Direction().XYZ() ^ axes[2].Direction().XYZ();
+ if ( isOk )
+ isOk = ( !axes[0].Direction().IsParallel( axes[1].Direction(), theAngTol ) &&
+ !axes[1].Direction().IsParallel( axes[2].Direction(), theAngTol ) &&
+ !axes[2].Direction().IsParallel( axes[0].Direction(), theAngTol ) &&
+ !norm01.IsParallel( norm12, theAngTol ) );
+ if ( isOk )
+ myAxesPreview->SetArrows( axes, myAxesLen );
+
+ myAxesPreview->SetVisibility( isOk );
+
+ return isOk;
+}
+
+//================================================================================
+/*!
+ * \brief Makes axes orthogonal if necessary
+ */
+//================================================================================
+
+void StdMeshersGUI_CartesianParamCreator::onOrthogonalAxes(bool isOrtho)
+{
+ if ( !isOrtho )
+ {
+ updateAxesPreview();
+ return;
+ }
+
+ std::multimap< int, int > ageOfAxis;
+ gp_XYZ dirs[3];
+ SMESHGUI_SpinBox** spins[3] = { &myXDirSpin[0], &myYDirSpin[0], &myZDirSpin[0] };
+ int nbOk = 0, isOk;
+ for ( int iAx = 0; iAx < 3; ++iAx )
+ {
+ dirs[iAx].SetCoord( spins[iAx][0]->GetValue(),
+ spins[iAx][1]->GetValue(),
+ spins[iAx][2]->GetValue());
+ if (( isOk = ( dirs[iAx].Modulus() > 1e-100 )))
+ ageOfAxis.insert( std::make_pair( myDirTic[iAx], iAx ));
+ else
+ ageOfAxis.insert( std::make_pair( -1, iAx ));
+ nbOk += isOk;
+ }
+ switch ( nbOk )
+ {
+ case 0:
+ {
+ dirs[0].SetCoord( 1, 0, 0 );
+ dirs[1].SetCoord( 0, 1, 0 );
+ dirs[2].SetCoord( 0, 0, 1 );
+ break;
+ }
+ case 1:
+ {
+ int iOk = ageOfAxis.rbegin()->second;
+ get3Dirs( iOk, dirs );
+ break;
+ }
+ default:
+ std::multimap< int, int >::reverse_iterator ag2ax = ageOfAxis.rbegin();
+ int iOk1 = ag2ax->second;
+ int iOk2 = (++ag2ax)->second;
+ int iKo = (++ag2ax)->second;
+ if ( gp_Vec( dirs[ iOk1 ]).IsParallel( gp_Vec( dirs[ iOk2 ]), theAngTol ))
+ std::swap( iOk2, iKo );
+ if ( gp_Vec( dirs[ iOk1 ]).IsParallel( gp_Vec( dirs[ iOk2 ]), theAngTol ))
+ {
+ get3Dirs( iOk1, dirs );
+ }
+ else
+ {
+ dirs[ iKo ] = dirs[ iOk1 ] ^ dirs[ iOk2 ];
+ dirs[ iOk2 ] = dirs[ iKo ] ^ dirs[ iOk1 ];
+ if ( ( iOk1+1 ) % 3 != iOk2 )
+ dirs[ iKo ].Reverse();
+ }
+ }
+
+ for ( int iAx = 0; iAx < 3; ++iAx )
+ {
+ double size = dirs[iAx].Modulus();
+ if ( size > 1e-100 )
+ dirs[iAx] /= size;
+ for (int i = 0; i < 3; ++i )
+ {
+ bool isBlocked = spins[iAx][i]->blockSignals( true );
+ spins[iAx][i]->SetValue( dirs[iAx].Coord( i+1 ));
+ spins[iAx][i]->blockSignals( isBlocked );
+ }
+ }
+
+ updateAxesPreview();
+}
+
+//================================================================================
+/*!
+ * \brief Increment myDirTic and update the preview of axes
+ */
+//================================================================================
+
+void StdMeshersGUI_CartesianParamCreator::onAxisDirChange(const QString&)
+{
+ QObject* changedSpin = sender();
+ SMESHGUI_SpinBox** spins[3] = { &myXDirSpin[0], &myYDirSpin[0], &myZDirSpin[0] };
+ for ( int iAx = 0; iAx < 3; ++iAx )
+ if ( spins[iAx][0] == changedSpin ||
+ spins[iAx][1] == changedSpin ||
+ spins[iAx][2] == changedSpin )
+ {
+ myDirTic[ iAx ] = 1 + Max( Max( myDirTic[0], myDirTic[1] ), myDirTic[2] );
+ break;
+ }
+
+ onOrthogonalAxes( myOrthogonalChk->isChecked() );
+}
+
+//================================================================================
+/*!
+ * \brief Sets axis direction by a selected EDGE
+ */
+//================================================================================
+
+void StdMeshersGUI_CartesianParamCreator::onSelectionChange()
+{
+ int iAxis = myAxisBtnGrp->checkedId();
+ if ( iAxis < 0 )
+ return;
+
+ SALOME_ListIO aList;
+ SMESHGUI::GetSMESHGUI()->selectionMgr()->selectedObjects(aList);
+
+ TopoDS_Shape edge, shape;
+ for( SALOME_ListIteratorOfListIO anIt( aList ); anIt.More(); anIt.Next() )
+ {
+ GEOM::GEOM_Object_var go = SMESH::IObjectToInterface( anIt.Value() );
+ if ( GEOMBase::GetShape( go, shape ) && shape.ShapeType() == TopAbs_EDGE )
+ {
+ if ( !edge.IsNull() )
+ return; // several EDGEs selected
+ edge = shape;
+ }
+ }
+ if ( edge.IsNull() )
+ return;
+
+ TopoDS_Shape vv[2];
+ TopoDS_Iterator vIt( edge );
+ for ( ; vIt.More() && vv[1].IsNull(); vIt.Next() )
+ vv[ !vv[0].IsNull() ] = vIt.Value();
+
+ gp_Pnt pp[2];
+ if ( !GEOMBase::VertexToPoint( vv[0], pp[0] ) ||
+ !GEOMBase::VertexToPoint( vv[1], pp[1] ))
+ return;
+
+ SMESHGUI_SpinBox** spins[3] = { &myXDirSpin[0], &myYDirSpin[0], &myZDirSpin[0] };
+
+ gp_Vec newDir( pp[0], pp[1] );
+ gp_Vec curDir( spins[iAxis][0]->GetValue(),
+ spins[iAxis][1]->GetValue(),
+ spins[iAxis][2]->GetValue());
+ if ( newDir * curDir < 0 )
+ newDir.Reverse();
+
+ double size = newDir.Magnitude();
+ if ( size < 1e-100 )
+ return;
+ newDir /= size;
+
+ for (int i = 0; i < 3; ++i )
+ {
+ bool isBlocked = spins[iAxis][i]->blockSignals( true );
+ spins[iAxis][i]->SetValue( newDir.Coord( i+1 ));
+ spins[iAxis][i]->blockSignals( isBlocked );
+ }
+ myDirTic[ iAxis ] = 1 + Max( Max( myDirTic[0], myDirTic[1] ), myDirTic[2] );
+
+ onOrthogonalAxes( myOrthogonalChk->isChecked() );
+}
+
+//================================================================================
+/*!
+ * \brief Sets axes at which number of hexahedra is maximal
+ */
+//================================================================================
+
+void StdMeshersGUI_CartesianParamCreator::onOptimalAxes(bool)
+{
+ StdMeshers::StdMeshers_CartesianParameters3D_var h =
+ StdMeshers::StdMeshers_CartesianParameters3D::_narrow( hypothesis() );
+ if ( h->_is_nil() )
+ return;
+
+ QString shapeEntry = getMainShapeEntry();
+ if ( shapeEntry.isEmpty() )
+ return;
+
+ Handle(SALOME_InteractiveObject) io =
+ new SALOME_InteractiveObject( shapeEntry.toStdString().c_str(), "GEOM" );
+ GEOM::GEOM_Object_var geomObj = SMESH::IObjectToInterface( io );
+ if ( geomObj->_is_nil() )
+ return;
+
+ SMESH::DirStruct axDirs[3];
+ h->ComputeOptimalAxesDirs( geomObj,
+ myOrthogonalChk->isChecked(),
+ axDirs[0],
+ axDirs[1],
+ axDirs[2]);
+
+ SMESHGUI_SpinBox** spins[3] = { &myXDirSpin[0], &myYDirSpin[0], &myZDirSpin[0] };
+ for ( int iAx = 0; iAx < 3; ++iAx )
+ {
+ double coords[3] = { axDirs[iAx].PS.x, axDirs[iAx].PS.y, axDirs[iAx].PS.z };
+ for (int i = 0; i < 3; ++i )
+ {
+ bool isBlocked = spins[iAx][i]->blockSignals( true );
+ spins[iAx][i]->SetValue( coords[ i ]);
+ spins[iAx][i]->blockSignals( isBlocked );
+ }
+ }
+ updateAxesPreview();
+}
+
+//================================================================================
+/*!
+ * \brief Sets axes || to the axes of global CS
+ */
+//================================================================================
+
+void StdMeshersGUI_CartesianParamCreator::onResetAxes(bool)
+{
+ SMESHGUI_SpinBox** spins[3] = { &myXDirSpin[0], &myYDirSpin[0], &myZDirSpin[0] };
+ for ( int iAx = 0; iAx < 3; ++iAx )
+ {
+ for (int i = 0; i < 3; ++i )
+ {
+ bool isBlocked = spins[iAx][i]->blockSignals( true );
+ spins[iAx][i]->SetValue( iAx == i ? 1. : 0. );
+ spins[iAx][i]->blockSignals( isBlocked );
+ }
+ myDirTic[iAx] = 0;
+ }
+ updateAxesPreview();
+}
+
+//================================================================================
+/*!
+ * \brief SLOT called when the grid definintion mode changes
+ */
+//================================================================================
+
+void StdMeshersGUI_CartesianParamCreator::onGridModeChanged(int)
+{
+ bool haveSpacing = ( myAxisTabs[0]->isGridBySpacing() ||
+ myAxisTabs[1]->isGridBySpacing() ||
+ myAxisTabs[2]->isGridBySpacing() );
+
+ myFixedPointGrp->setEnabled( haveSpacing );
+}
diff --git a/src/StdMeshersGUI/StdMeshersGUI_CartesianParamCreator.h b/src/StdMeshersGUI/StdMeshersGUI_CartesianParamCreator.h
index 1187bb90b..1a9fcd51e 100644
--- a/src/StdMeshersGUI/StdMeshersGUI_CartesianParamCreator.h
+++ b/src/StdMeshersGUI/StdMeshersGUI_CartesianParamCreator.h
@@ -42,6 +42,7 @@
class QAbstractItemModel;
class QButtonGroup;
class QCheckBox;
+class QGroupBox;
class QLineEdit;
class QListWidget;
class QListWidgetItem;
@@ -51,6 +52,7 @@ class QStyleOptionViewItem;
class QTreeWidget;
class QTreeWidgetItem;
class QWidget;
+class SMESHGUI_MeshEditPreview;
class SMESHGUI_SpinBox;
namespace StdMeshersGUI
@@ -79,6 +81,9 @@ namespace StdMeshersGUI
SMESH::double_array* getCoordinates();
void getSpacing(SMESH::string_array_out funs, SMESH::double_array_out points) const;
+ signals:
+ void gridModeChanged(int);
+
private slots:
void onInsert();
void onDelete();
@@ -126,19 +131,40 @@ public:
StdMeshersGUI_CartesianParamCreator( const QString& aHypType );
virtual ~StdMeshersGUI_CartesianParamCreator();
- virtual bool checkParams( QString& ) const;
- virtual QString helpPage() const;
+ virtual bool checkParams( QString& ) const;
+ virtual QString helpPage() const;
protected:
virtual QFrame* buildFrame();
virtual void retrieveParams() const;
virtual QString storeParams() const;
+private slots:
+ bool updateAxesPreview();
+ void onOrthogonalAxes(bool);
+ void onAxisDirChange(const QString&);
+ void onSelectionChange();
+ void onOptimalAxes(bool);
+ void onResetAxes(bool);
+ void onGridModeChanged(int);
+
private:
QLineEdit* myName;
SMESHGUI_SpinBox* myThreshold;
QCheckBox* myAddEdges;
+
StdMeshersGUI::GridAxisTab* myAxisTabs[3];
+ QGroupBox* myFixedPointGrp;
+ SMESHGUI_SpinBox* myPointSpin[3];
+ QCheckBox* myOrthogonalChk;
+ QButtonGroup* myAxisBtnGrp;
+ SMESHGUI_SpinBox* myXDirSpin[3];
+ SMESHGUI_SpinBox* myYDirSpin[3];
+ SMESHGUI_SpinBox* myZDirSpin[3];
+ SMESHGUI_MeshEditPreview* myAxesPreview;
+ double myOrigin[3];
+ double myAxesLen;
+ int myDirTic[3];
};
#endif // STDMESHERSGUI_CartesianParamCreator_H
diff --git a/src/StdMeshersGUI/StdMeshers_msg_en.ts b/src/StdMeshersGUI/StdMeshers_msg_en.ts
index f2ccb30f8..8b94762e7 100644
--- a/src/StdMeshersGUI/StdMeshers_msg_en.ts
+++ b/src/StdMeshersGUI/StdMeshers_msg_en.ts
@@ -529,6 +529,30 @@
AXIS_Z
Axis Z
+
+ INVALID_AXES_DIR
+ Invalid directions of axes
+
+
+ FIXED_POINT
+ Fixed Point
+
+
+ AXES_DIRECTION
+ Directions of Axes
+
+
+ ORTHOGONAL_AXES
+ Orthogonal Axes
+
+
+ OPTIMAL_AXES
+ Optimal Axes
+
+
+ RESET_AXES
+ Reset
+
StdMeshersGUI::GridAxisTab
diff --git a/src/StdMeshers_I/StdMeshers_CartesianParameters3D_i.cxx b/src/StdMeshers_I/StdMeshers_CartesianParameters3D_i.cxx
index 3db734054..5b383a0f5 100644
--- a/src/StdMeshers_I/StdMeshers_CartesianParameters3D_i.cxx
+++ b/src/StdMeshers_I/StdMeshers_CartesianParameters3D_i.cxx
@@ -224,6 +224,102 @@ void StdMeshers_CartesianParameters3D_i::GetGridSpacing(SMESH::string_array_out
}
}
+//=======================================================================
+//function : SetAxesDirs
+//purpose : Set custom direction of axes
+//=======================================================================
+
+void StdMeshers_CartesianParameters3D_i::SetAxesDirs(const SMESH::DirStruct& xDir,
+ const SMESH::DirStruct& yDir,
+ const SMESH::DirStruct& zDir)
+ throw (SALOME::SALOME_Exception)
+{
+ double coords[9];
+ coords[0] = xDir.PS.x;
+ coords[1] = xDir.PS.y;
+ coords[2] = xDir.PS.z;
+ coords[3] = yDir.PS.x;
+ coords[4] = yDir.PS.y;
+ coords[5] = yDir.PS.z;
+ coords[6] = zDir.PS.x;
+ coords[7] = zDir.PS.y;
+ coords[8] = zDir.PS.z;
+ try {
+ this->GetImpl()->SetAxisDirs(coords);
+
+ SMESH::TPythonDump() << _this() << ".SetAxesDirs( "
+ << xDir << ", "
+ << yDir << ", "
+ << zDir << " )";
+ }
+ catch ( SALOME_Exception& S_ex ) {
+ THROW_SALOME_CORBA_EXCEPTION( S_ex.what(), SALOME::BAD_PARAM );
+ }
+}
+
+//=======================================================================
+//function : GetAxesDirs
+//purpose : Returns direction of axes
+//=======================================================================
+
+void StdMeshers_CartesianParameters3D_i::GetAxesDirs(SMESH::DirStruct& xDir,
+ SMESH::DirStruct& yDir,
+ SMESH::DirStruct& zDir)
+{
+ const double* coords = GetImpl()->GetAxisDirs();
+ xDir.PS.x = coords[0];
+ xDir.PS.y = coords[1];
+ xDir.PS.z = coords[2];
+ yDir.PS.x = coords[3];
+ yDir.PS.y = coords[4];
+ yDir.PS.z = coords[5];
+ zDir.PS.x = coords[6];
+ zDir.PS.y = coords[7];
+ zDir.PS.z = coords[8];
+}
+
+//=======================================================================
+//function : SetFixedPoint
+//purpose : * Set/unset a fixed point, at which a node will be created provided that grid
+// * is defined by spacing in all directions
+//=======================================================================
+
+void StdMeshers_CartesianParameters3D_i::SetFixedPoint(const SMESH::PointStruct& ps,
+ CORBA::Boolean toUnset)
+{
+ double p[3] = { ps.x, ps.y, ps.z };
+ GetImpl()->SetFixedPoint( p, toUnset );
+
+ if ( toUnset )
+ SMESH::TPythonDump() << _this() << ".SetFixedPoint([0,0,0], True)";
+ else
+ SMESH::TPythonDump() << _this() << ".SetFixedPoint(" << p << ", " << toUnset << " )";
+}
+
+//=======================================================================
+//function : GetFixedPoint
+//purpose : Returns a fixed point
+//=======================================================================
+
+CORBA::Boolean StdMeshers_CartesianParameters3D_i::GetFixedPoint(SMESH::PointStruct& ps)
+{
+ double p[3];
+ if ( GetImpl()->GetFixedPoint( p ) )
+ {
+ ps.x = p[0];
+ ps.y = p[1];
+ ps.z = p[2];
+ return true;
+ }
+ else
+ {
+ ps.x = 0.;
+ ps.y = 0.;
+ ps.z = 0.;
+ }
+ return false;
+}
+
//=======================================================================
//function : SetToAddEdges
//purpose : Enables implementation of geometrical edges into the mesh.
@@ -248,7 +344,7 @@ CORBA::Boolean StdMeshers_CartesianParameters3D_i::GetToAddEdges()
//=======================================================================
//function : IsGridBySpacing
-//purpose : Return true if the grid is defined by spacing functions and
+//purpose : Return true if the grid is defined by spacing functions and
// not by node coordinates
//=======================================================================
@@ -257,6 +353,37 @@ CORBA::Boolean StdMeshers_CartesianParameters3D_i::IsGridBySpacing(CORBA::Short
return this->GetImpl()->IsGridBySpacing(axis);
}
+//=======================================================================
+//function : ComputeOptimalAxesDirs
+//purpose : Returns axes at which number of hexahedra is maximal
+//=======================================================================
+
+void StdMeshers_CartesianParameters3D_i::
+ComputeOptimalAxesDirs(GEOM::GEOM_Object_ptr go,
+ CORBA::Boolean isOrthogonal,
+ SMESH::DirStruct& xDir,
+ SMESH::DirStruct& yDir,
+ SMESH::DirStruct& zDir)
+ throw (SALOME::SALOME_Exception)
+{
+ TopoDS_Shape shape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( go );
+ if ( shape.IsNull() )
+ THROW_SALOME_CORBA_EXCEPTION( "Null shape", SALOME::BAD_PARAM );
+
+ double c[9];
+ ::StdMeshers_CartesianParameters3D::ComputeOptimalAxesDirs( shape, isOrthogonal, c );
+
+ xDir.PS.x = c[0];
+ xDir.PS.y = c[1];
+ xDir.PS.z = c[2];
+ yDir.PS.x = c[3];
+ yDir.PS.y = c[4];
+ yDir.PS.z = c[5];
+ zDir.PS.x = c[6];
+ zDir.PS.y = c[7];
+ zDir.PS.z = c[8];
+}
+
//=======================================================================
//function : ComputeCoordinates
//purpose : Computes node coordinates by spacing functions
@@ -268,13 +395,13 @@ StdMeshers_CartesianParameters3D_i::ComputeCoordinates(CORBA::Double
const SMESH::string_array& spaceFuns,
const SMESH::double_array& points,
const char* axisName )
- throw (SALOME::SALOME_Exception)
+ throw (SALOME::SALOME_Exception)
{
vector xFuns;
vector xPoints, coords;
_array2vec( spaceFuns, xFuns, (const char*) );
_array2vec( points, xPoints, );
-
+
try {
this->GetImpl()->ComputeCoordinates( x0, x1, xFuns, xPoints, coords, axisName );
}
diff --git a/src/StdMeshers_I/StdMeshers_CartesianParameters3D_i.hxx b/src/StdMeshers_I/StdMeshers_CartesianParameters3D_i.hxx
index abdda05f4..74df5de91 100644
--- a/src/StdMeshers_I/StdMeshers_CartesianParameters3D_i.hxx
+++ b/src/StdMeshers_I/StdMeshers_CartesianParameters3D_i.hxx
@@ -83,6 +83,22 @@ class STDMESHERS_I_EXPORT StdMeshers_CartesianParameters3D_i:
void GetGridSpacing(SMESH::string_array_out xSpaceFunctions,
SMESH::double_array_out xInternalPoints,
CORBA::Short axis) throw (SALOME::SALOME_Exception);
+ /*!
+ * Set custom direction of axes
+ */
+ void SetAxesDirs(const SMESH::DirStruct& x,
+ const SMESH::DirStruct& y,
+ const SMESH::DirStruct& z) throw (SALOME::SALOME_Exception);
+ void GetAxesDirs(SMESH::DirStruct& x,
+ SMESH::DirStruct& y,
+ SMESH::DirStruct& z);
+ /*!
+ * Set/unset a fixed point, at which a node will be created provided that grid
+ * is defined by spacing in all directions
+ */
+ void SetFixedPoint(const ::SMESH::PointStruct& p, CORBA::Boolean toUnset);
+ CORBA::Boolean GetFixedPoint(::SMESH::PointStruct& p);
+
/*!
* \brief Enables implementation of geometrical edges into the mesh. If this feature
@@ -98,6 +114,14 @@ class STDMESHERS_I_EXPORT StdMeshers_CartesianParameters3D_i:
*/
CORBA::Boolean IsGridBySpacing(CORBA::Short axis);
+ /*!
+ * Returns axes at which number of hexahedra is maximal
+ */
+ void ComputeOptimalAxesDirs(GEOM::GEOM_Object_ptr shape,
+ CORBA::Boolean isOrthogonal,
+ SMESH::DirStruct& x,
+ SMESH::DirStruct& y,
+ SMESH::DirStruct& z) throw (SALOME::SALOME_Exception);
/*!
* \brief Computes node coordinates by spacing functions
* \param x0 - lower coordinate