From 512916b107f163a97535d0326008d3edabf6c7ec Mon Sep 17 00:00:00 2001 From: eap Date: Wed, 6 Dec 2006 15:23:10 +0000 Subject: [PATCH] PAL13473 (Build repetitive mesh): New meshers implemented --- src/StdMeshers/Makefile.in | 26 +- .../StdMeshers_LayerDistribution.cxx | 148 ++ .../StdMeshers_LayerDistribution.hxx | 91 + src/StdMeshers/StdMeshers_NumberOfLayers.cxx | 162 ++ src/StdMeshers/StdMeshers_NumberOfLayers.hxx | 81 + src/StdMeshers/StdMeshers_Prism_3D.cxx | 1750 +++++++++++++++++ src/StdMeshers/StdMeshers_Prism_3D.hxx | 425 ++++ .../StdMeshers_ProjectionSource1D.cxx | 219 +++ .../StdMeshers_ProjectionSource1D.hxx | 142 ++ .../StdMeshers_ProjectionSource2D.cxx | 287 +++ .../StdMeshers_ProjectionSource2D.hxx | 155 ++ .../StdMeshers_ProjectionSource3D.cxx | 286 +++ .../StdMeshers_ProjectionSource3D.hxx | 153 ++ src/StdMeshers/StdMeshers_ProjectionUtils.cxx | 1241 ++++++++++++ src/StdMeshers/StdMeshers_ProjectionUtils.hxx | 198 ++ src/StdMeshers/StdMeshers_Projection_1D.cxx | 362 ++++ src/StdMeshers/StdMeshers_Projection_1D.hxx | 64 + src/StdMeshers/StdMeshers_Projection_2D.cxx | 638 ++++++ src/StdMeshers/StdMeshers_Projection_2D.hxx | 63 + src/StdMeshers/StdMeshers_Projection_3D.cxx | 438 +++++ src/StdMeshers/StdMeshers_Projection_3D.hxx | 61 + src/StdMeshers/StdMeshers_RadialPrism_3D.cxx | 372 ++++ src/StdMeshers/StdMeshers_RadialPrism_3D.hxx | 70 + 23 files changed, 7430 insertions(+), 2 deletions(-) create mode 100644 src/StdMeshers/StdMeshers_LayerDistribution.cxx create mode 100644 src/StdMeshers/StdMeshers_LayerDistribution.hxx create mode 100644 src/StdMeshers/StdMeshers_NumberOfLayers.cxx create mode 100644 src/StdMeshers/StdMeshers_NumberOfLayers.hxx create mode 100644 src/StdMeshers/StdMeshers_Prism_3D.cxx create mode 100644 src/StdMeshers/StdMeshers_Prism_3D.hxx create mode 100644 src/StdMeshers/StdMeshers_ProjectionSource1D.cxx create mode 100644 src/StdMeshers/StdMeshers_ProjectionSource1D.hxx create mode 100644 src/StdMeshers/StdMeshers_ProjectionSource2D.cxx create mode 100644 src/StdMeshers/StdMeshers_ProjectionSource2D.hxx create mode 100644 src/StdMeshers/StdMeshers_ProjectionSource3D.cxx create mode 100644 src/StdMeshers/StdMeshers_ProjectionSource3D.hxx create mode 100644 src/StdMeshers/StdMeshers_ProjectionUtils.cxx create mode 100644 src/StdMeshers/StdMeshers_ProjectionUtils.hxx create mode 100644 src/StdMeshers/StdMeshers_Projection_1D.cxx create mode 100644 src/StdMeshers/StdMeshers_Projection_1D.hxx create mode 100644 src/StdMeshers/StdMeshers_Projection_2D.cxx create mode 100644 src/StdMeshers/StdMeshers_Projection_2D.hxx create mode 100644 src/StdMeshers/StdMeshers_Projection_3D.cxx create mode 100644 src/StdMeshers/StdMeshers_Projection_3D.hxx create mode 100644 src/StdMeshers/StdMeshers_RadialPrism_3D.cxx create mode 100644 src/StdMeshers/StdMeshers_RadialPrism_3D.hxx diff --git a/src/StdMeshers/Makefile.in b/src/StdMeshers/Makefile.in index b2a3fa7ff..d81355de9 100644 --- a/src/StdMeshers/Makefile.in +++ b/src/StdMeshers/Makefile.in @@ -51,7 +51,18 @@ EXPORT_HEADERS = \ StdMeshers_AutomaticLength.hxx \ StdMeshers_Distribution.hxx \ StdMeshers_QuadranglePreference.hxx \ - StdMeshers_QuadraticMesh.hxx + StdMeshers_QuadraticMesh.hxx \ + StdMeshers_NumberOfLayers.hxx \ + StdMeshers_Prism_3D.hxx \ + StdMeshers_ProjectionSource1D.hxx \ + StdMeshers_ProjectionSource2D.hxx \ + StdMeshers_ProjectionSource3D.hxx \ + StdMeshers_Projection_1D.hxx \ + StdMeshers_Projection_2D.hxx \ + StdMeshers_Projection_3D.hxx \ + StdMeshers_RadialPrism_3D.hxx \ + StdMeshers_ProjectionUtils.hxx \ + StdMeshers_LayerDistribution.hxx EXPORT_PYSCRIPTS = @@ -78,7 +89,18 @@ LIB_SRC = \ StdMeshers_AutomaticLength.cxx \ StdMeshers_Distribution.cxx \ StdMeshers_QuadranglePreference.cxx \ - StdMeshers_QuadraticMesh.cxx + StdMeshers_QuadraticMesh.cxx \ + StdMeshers_NumberOfLayers.cxx \ + StdMeshers_Prism_3D.cxx \ + StdMeshers_ProjectionSource1D.cxx \ + StdMeshers_ProjectionSource2D.cxx \ + StdMeshers_ProjectionSource3D.cxx \ + StdMeshers_Projection_1D.cxx \ + StdMeshers_Projection_2D.cxx \ + StdMeshers_Projection_3D.cxx \ + StdMeshers_RadialPrism_3D.cxx \ + StdMeshers_ProjectionUtils.cxx \ + StdMeshers_LayerDistribution.cxx LIB_SERVER_IDL = diff --git a/src/StdMeshers/StdMeshers_LayerDistribution.cxx b/src/StdMeshers/StdMeshers_LayerDistribution.cxx new file mode 100644 index 000000000..42d99c8ed --- /dev/null +++ b/src/StdMeshers/StdMeshers_LayerDistribution.cxx @@ -0,0 +1,148 @@ +// SMESH SMESH : idl implementation based on 'SMESH' unit's classes +// +// Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// +// +// File : StdMeshers_LayerDistribution.cxx +// Author : Edward AGAPOV +// Module : SMESH +// $Header$ + +#include "StdMeshers_LayerDistribution.hxx" + +#include "utilities.h" + +using namespace std; + + +//============================================================================= +/*! + * StdMeshers_LayerDistribution::StdMeshers_LayerDistribution + * + * Constructor + */ +//============================================================================= + +StdMeshers_LayerDistribution::StdMeshers_LayerDistribution(int hypId, int studyId, + SMESH_Gen * gen) + : SMESH_Hypothesis(hypId, studyId, gen) +{ + _name = "LayerDistribution"; // used by RadialPrism_3D + _param_algo_dim = 3; // 3D + myHyp = 0; +} + +//============================================================================= +/*! + * StdMeshers_LayerDistribution::~StdMeshers_LayerDistribution + * + * Destructor + */ +//============================================================================= + +StdMeshers_LayerDistribution::~StdMeshers_LayerDistribution() +{ + MESSAGE( "StdMeshers_LayerDistribution::~StdMeshers_LayerDistribution" ); +} + +//============================================================================= + /*! + * \brief Sets 1D hypothesis specifying distribution of layers + * \param hyp1D - 1D hypothesis + */ +//============================================================================= + +void StdMeshers_LayerDistribution::SetLayerDistribution(SMESH_Hypothesis* hyp1D) + throw ( SALOME_Exception ) +{ + if ( myHyp != hyp1D ) { + if ( myHyp && hyp1D->GetDim() != 1 ) + throw SALOME_Exception(LOCALIZED("1D hypothesis is expected")); + myHyp = hyp1D; + } + std::ostringstream os; + if ( myHyp ) + myHyp->SaveTo( os ); + + if ( mySavedHyp != os.str() ) + NotifySubMeshesHypothesisModification(); + + mySavedHyp = os.str(); +} + +//============================================================================= +/*! + * Servant saves and loads my hypothesis + */ +//============================================================================= + +ostream & StdMeshers_LayerDistribution::SaveTo(ostream & save) +{ + return save; +} + +//============================================================================= +/*! + * Servant saves and loads my hypothesis + */ +//============================================================================= + +istream & StdMeshers_LayerDistribution::LoadFrom(istream & load) +{ + return load; +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +ostream & operator <<(ostream & save, StdMeshers_LayerDistribution & hyp) +{ + return hyp.SaveTo( save ); +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +istream & operator >>(istream & load, StdMeshers_LayerDistribution & hyp) +{ + return hyp.LoadFrom( load ); +} + +//================================================================================ +/*! + * \brief Initialize start and end length by the mesh built on the geometry + * \param theMesh - the built mesh + * \param theShape - the geometry of interest + * \retval bool - true if parameter values have been successfully defined + */ +//================================================================================ + +bool StdMeshers_LayerDistribution::SetParametersByMesh(const SMESH_Mesh* , + const TopoDS_Shape& ) +{ + return false; +} diff --git a/src/StdMeshers/StdMeshers_LayerDistribution.hxx b/src/StdMeshers/StdMeshers_LayerDistribution.hxx new file mode 100644 index 000000000..08c22693e --- /dev/null +++ b/src/StdMeshers/StdMeshers_LayerDistribution.hxx @@ -0,0 +1,91 @@ +// SMESH SMESH : idl implementation based on 'SMESH' unit's calsses +// +// Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// +// +// File : StdMeshers_LayerDistribution.hxx +// Author : Edward AGAPOV +// Module : SMESH +// $Header$ + +#ifndef _SMESH_LayerDistribution_HXX_ +#define _SMESH_LayerDistribution_HXX_ + +#include "SMESH_Hypothesis.hxx" +#include "Utils_SALOME_Exception.hxx" + +#include + +class SMESH_Gen; + +// ========================================================= +// ========================================================= +/*! + * This hypothesis is used by "Radial prism" algorithm. + * It specifies 1D hypothesis defining distribution of segments between the internal + * and the external surfaces. + */ +// ========================================================= +// ========================================================= + +class StdMeshers_LayerDistribution: public SMESH_Hypothesis +{ +public: + // Constructor + StdMeshers_LayerDistribution( int hypId, int studyId, SMESH_Gen * gen ); + // Destructor + virtual ~StdMeshers_LayerDistribution(); + + /*! + * \brief Sets 1D hypothesis specifying distribution of layers + * \param hyp1D - 1D hypothesis + */ + void SetLayerDistribution(SMESH_Hypothesis* hyp1D) + throw ( SALOME_Exception ); + + /*! + * \brief Returns 1D hypothesis specifying distribution of layers + * \retval SMESH::SMESH_Hypothesis_ptr - 1D hypothesis + */ + SMESH_Hypothesis* GetLayerDistribution() const { return myHyp; } + + virtual std::ostream & SaveTo(std::ostream & save); + virtual std::istream & LoadFrom(std::istream & load); + friend std::ostream & operator <<(std::ostream & save, StdMeshers_LayerDistribution & hyp); + friend std::istream & operator >>(std::istream & load, StdMeshers_LayerDistribution & hyp); + + /*! + * \brief Initialize parameters by the mesh built on the geometry + * \param theMesh - the built mesh + * \param theShape - the geometry of interest + * \retval bool - true if parameter values have been successfully defined + * + * Implementation does noting + */ + virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); + +protected: + SMESH_Hypothesis* myHyp; + std::string mySavedHyp; +}; + +#endif + diff --git a/src/StdMeshers/StdMeshers_NumberOfLayers.cxx b/src/StdMeshers/StdMeshers_NumberOfLayers.cxx new file mode 100644 index 000000000..c1bab0f62 --- /dev/null +++ b/src/StdMeshers/StdMeshers_NumberOfLayers.cxx @@ -0,0 +1,162 @@ +// SMESH SMESH : idl implementation based on 'SMESH' unit's classes +// +// Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// +// +// File : StdMeshers_NumberOfLayers.cxx +// Author : Edward AGAPOV +// Module : SMESH +// $Header$ + +#include "StdMeshers_NumberOfLayers.hxx" + + +#include "utilities.h" + +using namespace std; + + +//============================================================================= +/*! + * StdMeshers_NumberOfLayers::StdMeshers_NumberOfLayers + * + * Constructor + */ +//============================================================================= + +StdMeshers_NumberOfLayers::StdMeshers_NumberOfLayers(int hypId, int studyId, + SMESH_Gen * gen) + : SMESH_Hypothesis(hypId, studyId, gen) +{ + _name = "NumberOfLayers"; // used by RadialPrism_3D + _param_algo_dim = 3; // 3D + _nbLayers = 1; +} + +//============================================================================= +/*! + * StdMeshers_NumberOfLayers::~StdMeshers_NumberOfLayers + * + * Destructor + */ +//============================================================================= + +StdMeshers_NumberOfLayers::~StdMeshers_NumberOfLayers() +{ + MESSAGE( "StdMeshers_NumberOfLayers::~StdMeshers_NumberOfLayers" ); +} + +//============================================================================= +/*! + * StdMeshers_NumberOfLayers::SetNumberOfLayers + * + * Sets parameter value + */ +//============================================================================= + +void StdMeshers_NumberOfLayers::SetNumberOfLayers(int numberOfLayers) + throw ( SALOME_Exception ) +{ + if ( _nbLayers != numberOfLayers ) { + if ( numberOfLayers <= 0 ) + throw SALOME_Exception(LOCALIZED("numberOfLayers must be positive")); + _nbLayers = numberOfLayers; + + NotifySubMeshesHypothesisModification(); + } +} + +//============================================================================= +/*! + * StdMeshers_NumberOfLayers::GetNumberOfLayers + * + * Returns parameter value + */ +//============================================================================= + +int StdMeshers_NumberOfLayers::GetNumberOfLayers() const +{ + return _nbLayers; +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +ostream & StdMeshers_NumberOfLayers::SaveTo(ostream & save) +{ + save << _nbLayers; + return save; +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +istream & StdMeshers_NumberOfLayers::LoadFrom(istream & load) +{ + bool isOK = true; + isOK = (load >> _nbLayers); + if (!isOK) + load.clear(ios::badbit | load.rdstate()); + return load; +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +ostream & operator <<(ostream & save, StdMeshers_NumberOfLayers & hyp) +{ + return hyp.SaveTo( save ); +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +istream & operator >>(istream & load, StdMeshers_NumberOfLayers & hyp) +{ + return hyp.LoadFrom( load ); +} + +//================================================================================ +/*! + * \brief Initialize start and end length by the mesh built on the geometry + * \param theMesh - the built mesh + * \param theShape - the geometry of interest + * \retval bool - true if parameter values have been successfully defined + */ +//================================================================================ + +bool StdMeshers_NumberOfLayers::SetParametersByMesh(const SMESH_Mesh* , + const TopoDS_Shape& ) +{ + return false; +} diff --git a/src/StdMeshers/StdMeshers_NumberOfLayers.hxx b/src/StdMeshers/StdMeshers_NumberOfLayers.hxx new file mode 100644 index 000000000..d89725589 --- /dev/null +++ b/src/StdMeshers/StdMeshers_NumberOfLayers.hxx @@ -0,0 +1,81 @@ +// SMESH SMESH : idl implementation based on 'SMESH' unit's calsses +// +// Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// +// +// File : StdMeshers_NumberOfLayers.hxx +// Author : Edward AGAPOV +// Module : SMESH +// $Header$ + +#ifndef _SMESH_NumberOfLayers_HXX_ +#define _SMESH_NumberOfLayers_HXX_ + +#include "SMESH_Hypothesis.hxx" +#include "Utils_SALOME_Exception.hxx" + +class SMESH_Gen; + +// ========================================================= +// ========================================================= +/*! + * This hypothesis is used by "Radial prism" algorithm. + * It specifies number of segments between the internal + * and the external surfaces. + */ +// ========================================================= +// ========================================================= + +class StdMeshers_NumberOfLayers: public SMESH_Hypothesis +{ +public: + // Constructor + StdMeshers_NumberOfLayers( int hypId, int studyId, SMESH_Gen * gen ); + // Destructor + virtual ~StdMeshers_NumberOfLayers(); + + // Sets parameter value + void SetNumberOfLayers(int numberOfLayers) throw ( SALOME_Exception ); + + // Returns parameter value + int GetNumberOfLayers() const; + + virtual std::ostream & SaveTo(std::ostream & save); + virtual std::istream & LoadFrom(std::istream & load); + friend std::ostream & operator <<(std::ostream & save, StdMeshers_NumberOfLayers & hyp); + friend std::istream & operator >>(std::istream & load, StdMeshers_NumberOfLayers & hyp); + + /*! + * \brief Initialize parameters by the mesh built on the geometry + * \param theMesh - the built mesh + * \param theShape - the geometry of interest + * \retval bool - true if parameter values have been successfully defined + * + * Implementation does noting + */ + virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); + +protected: + int _nbLayers; +}; + +#endif + diff --git a/src/StdMeshers/StdMeshers_Prism_3D.cxx b/src/StdMeshers/StdMeshers_Prism_3D.cxx new file mode 100644 index 000000000..85b418088 --- /dev/null +++ b/src/StdMeshers/StdMeshers_Prism_3D.cxx @@ -0,0 +1,1750 @@ +// SMESH SMESH : implementaion of SMESH idl descriptions +// +// Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// +// +// File : StdMeshers_Prism_3D.cxx +// Module : SMESH +// Created : Fri Oct 20 11:37:07 2006 +// Author : Edward AGAPOV (eap) + + +#include "StdMeshers_Prism_3D.hxx" + +#include "StdMeshers_ProjectionUtils.hxx" +#include "SMESH_MeshEditor.hxx" +#include "SMDS_VolumeTool.hxx" +#include "SMDS_VolumeOfNodes.hxx" +#include "SMDS_EdgePosition.hxx" + +#include "utilities.h" + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +#define RETURN_BAD_RESULT(msg) { MESSAGE(msg); return false; } +#define gpXYZ(n) gp_XYZ(n->X(),n->Y(),n->Z()) +#define SHOWYXZ(msg, xyz) // {\ +// gp_Pnt p (xyz); \ +// cout << msg << " ("<< p.X() << "; " <upper_bound( parameter ); + if ( u_col != columnsMap->begin() ) + --u_col; + return u_col; // return left column + } + + //================================================================================ + /*! + * \brief Return nodes around given parameter and a ratio + * \param column - node column + * \param param - parameter + * \param node1 - lower node + * \param node2 - upper node + * \retval double - ratio + */ + //================================================================================ + + double getRAndNodes( const TNodeColumn* column, + const double param, + const SMDS_MeshNode* & node1, + const SMDS_MeshNode* & node2) + { + if ( param == 1.0 || column->size() == 1) { + node1 = node2 = column->back(); + return 0; + } + + int i = int( param * ( column->size() - 1 )); + double u0 = double( i )/ double( column->size() - 1 ); + double r = ( param - u0 ) * ( column->size() - 1 ); + + node1 = (*column)[ i ]; + node2 = (*column)[ i + 1]; + return r; + } + + //================================================================================ + /*! + * \brief Compute boundary parameters of face parts + * \param nbParts - nb of parts to split columns into + * \param columnsMap - node columns of the face to split + * \param params - computed parameters + */ + //================================================================================ + + void splitParams( const int nbParts, + const TParam2ColumnMap* columnsMap, + vector< double > & params) + { + params.clear(); + params.reserve( nbParts + 1 ); + TParam2ColumnIt last_par_col = --columnsMap->end(); + double par = columnsMap->begin()->first; // 0. + double parLast = last_par_col->first; + params.push_back( par ); + for ( int i = 0; i < nbParts - 1; ++ i ) + { + double partSize = ( parLast - par ) / double ( nbParts - i ); + TParam2ColumnIt par_col = getColumn( columnsMap, par + partSize ); + if ( par_col->first == par ) { + ++par_col; + if ( par_col == last_par_col ) { + while ( i < nbParts - 1 ) + params.push_back( par + partSize * i++ ); + break; + } + } + par = par_col->first; + params.push_back( par ); + } + params.push_back( parLast ); // 1. + } +} + +//======================================================================= +//function : StdMeshers_Prism_3D +//purpose : +//======================================================================= + +StdMeshers_Prism_3D::StdMeshers_Prism_3D(int hypId, int studyId, SMESH_Gen* gen) + :SMESH_3D_Algo(hypId, studyId, gen) +{ + _name = "Prism_3D"; + _shapeType = (1 << TopAbs_SHELL) | (1 << TopAbs_SOLID); // 1 bit per shape type + myProjectTriangles = false; +} + +//================================================================================ +/*! + * \brief Destructor + */ +//================================================================================ + +StdMeshers_Prism_3D::~StdMeshers_Prism_3D() +{} + +//======================================================================= +//function : CheckHypothesis +//purpose : +//======================================================================= + +bool StdMeshers_Prism_3D::CheckHypothesis(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + SMESH_Hypothesis::Hypothesis_Status& aStatus) +{ + // no hypothesis + aStatus = SMESH_Hypothesis::HYP_OK; + return true; +} + +//======================================================================= +//function : Compute +//purpose : +//======================================================================= + +bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theShape) +{ + myHelper = new SMESH_MesherHelper( theMesh ); + // to delete helper at exit from Compute() + std::auto_ptr helperDeleter( myHelper ); + + myHelper->IsQuadraticSubMesh( theShape ); + + // Analyse mesh and geomerty to find block subshapes and submeshes + if ( !myBlock.Init( myHelper, theShape )) + return false; + + SMESHDS_Mesh* meshDS = theMesh.GetMeshDS(); + + int volumeID = meshDS->ShapeToIndex( theShape ); + + + // To compute coordinates of a node inside a block, it is necessary to know + // 1. normalized parameters of the node by which + // 2. coordinates of node projections on all block sub-shapes are computed + + // So we fill projections on vertices at once as they are same for all nodes + myShapeXYZ.resize( myBlock.NbSubShapes() ); + for ( int iV = SMESH_Block::ID_FirstV; iV < SMESH_Block::ID_FirstE; ++iV ) { + myBlock.VertexPoint( iV, myShapeXYZ[ iV ]); + SHOWYXZ("V point " <first; // bottom TNode + if ( tBotNode.GetPositionType() != SMDS_TOP_FACE ) + continue; // node is not inside face + + // column nodes; middle part of the column are zero pointers + TNodeColumn& column = bot_column->second; + + // bottom node parameters and coords + gp_XYZ botParams = tBotNode.GetParams(); + myShapeXYZ[ ID_BOT_FACE ] = tBotNode.GetCoords(); + + // compute top node parameters + gp_XYZ topParams; + myShapeXYZ[ ID_TOP_FACE ] = gpXYZ( column.back() ); + gp_Pnt topCoords = myShapeXYZ[ ID_TOP_FACE ]; + if ( !myBlock.ComputeParameters( topCoords, topParams, ID_TOP_FACE )) + RETURN_BAD_RESULT("ComputeParameters() on the top face failed"); + + // vertical loop + TNodeColumn::iterator columnNodes = column.begin(); + for ( int z = 0; columnNodes != column.end(); ++columnNodes, ++z) + { + const SMDS_MeshNode* & node = *columnNodes; + if ( node ) continue; // skip bottom or top node + + // params of a node to create + double rz = (double) z / (double) ( column.size() - 1 ); + gp_XYZ params = botParams * ( 1 - rz ) + topParams * rz; + + // set coords on all faces and nodes + const int nbSideFaces = 4; + int sideFaceIDs[nbSideFaces] = { SMESH_Block::ID_Fx0z, + SMESH_Block::ID_Fx1z, + SMESH_Block::ID_F0yz, + SMESH_Block::ID_F1yz }; + for ( int iF = 0; iF < nbSideFaces; ++iF ) + if ( !setFaceAndEdgesXYZ( sideFaceIDs[ iF ], params, z )) + return false; + + // compute coords for a new node + gp_XYZ coords; + if ( !SMESH_Block::ShellPoint( params, myShapeXYZ, coords )) + RETURN_BAD_RESULT("SMESH_Block::ShellPoint() failed"); + + // create a node + node = meshDS->AddNode( coords.X(), coords.Y(), coords.Z() ); + meshDS->SetNodeInVolume( node, volumeID ); + } + } // loop on bottom nodes + + + // Create volumes + + SMESHDS_SubMesh* smDS = myBlock.SubMeshDS( ID_BOT_FACE ); + if ( !smDS ) RETURN_BAD_RESULT("Null submesh"); + + // loop on bottom mesh faces + SMDS_ElemIteratorPtr faceIt = smDS->GetElements(); + while ( faceIt->more() ) + { + const SMDS_MeshElement* face = faceIt->next(); + if ( !face || face->GetType() != SMDSAbs_Face ) + continue; + int nbNodes = face->NbNodes(); + if ( face->IsQuadratic() ) + nbNodes /= 2; + + // find node columns for each node + vector< const TNodeColumn* > columns( nbNodes ); + for ( int i = 0; i < nbNodes; ++i ) + { + const SMDS_MeshNode* n = face->GetNode( i ); + if ( n->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE ) { + bot_column = myBotToColumnMap.find( n ); + if ( bot_column == myBotToColumnMap.end() ) + RETURN_BAD_RESULT(" node column for a node not found"); + columns[ i ] = & bot_column->second; + } + else { + columns[ i ] = myBlock.GetNodeColumn( n ); + if ( !columns[ i ] ) + RETURN_BAD_RESULT(" node column not found for a node " << n->GetID() ); + } + } + // create prisms + AddPrisms( columns, myHelper ); + + } // loop on bottom mesh faces + + return true; +} + +//================================================================================ +/*! + * \brief Create prisms + * \param columns - columns of nodes generated from nodes of a mesh face + * \param helper - helper initialized by mesh and shape to add prisms to + */ +//================================================================================ + +void StdMeshers_Prism_3D::AddPrisms( vector & columns, + SMESH_MesherHelper* helper) +{ + SMESHDS_Mesh * meshDS = helper->GetMeshDS(); + int shapeID = helper->GetSubShapeID(); + + int nbNodes = columns.size(); + + // vertical loop on columns + for ( int z = 1; z < columns[0]->size(); ++z) + { + SMDS_MeshElement* vol = 0; + SMDS_VolumeTool vTool; + switch ( nbNodes ) { + + case 3: { + const SMDS_MeshNode* botNodes[3] = { (*columns[0])[z-1], + (*columns[1])[z-1], + (*columns[2])[z-1] }; + const SMDS_MeshNode* topNodes[3] = { (*columns[0])[z], + (*columns[1])[z], + (*columns[2])[z] }; + // assure good orientation + SMDS_VolumeOfNodes tmpVol ( botNodes[0], botNodes[1], botNodes[2], + topNodes[0], topNodes[1], topNodes[2]); + vTool.Set( &tmpVol ); + if ( vTool.IsForward() ) + vol = helper->AddVolume( botNodes[0], botNodes[1], botNodes[2], + topNodes[0], topNodes[1], topNodes[2]); + else + vol = helper->AddVolume( topNodes[0], topNodes[1], topNodes[2], + botNodes[0], botNodes[1], botNodes[2]); + break; + } + case 4: { + const SMDS_MeshNode* botNodes[4] = { (*columns[0])[z-1], (*columns[1])[z-1], + (*columns[2])[z-1], (*columns[3])[z-1] }; + const SMDS_MeshNode* topNodes[4] = { (*columns[0])[z], (*columns[1])[z], + (*columns[2])[z], (*columns[3])[z] }; + // assure good orientation + SMDS_VolumeOfNodes tmpVol ( botNodes[0], botNodes[1], botNodes[2], botNodes[3], + topNodes[0], topNodes[1], topNodes[2], topNodes[3]); + vTool.Set( &tmpVol ); + if ( vTool.IsForward() ) + vol = helper->AddVolume( botNodes[0], botNodes[1], botNodes[2], botNodes[3], + topNodes[0], topNodes[1], topNodes[2], topNodes[3]); + else + vol = helper->AddVolume( topNodes[0], topNodes[1], topNodes[2], topNodes[3], + botNodes[0], botNodes[1], botNodes[2], botNodes[3]); + break; + } + default: + // polyhedron + vector nodes( 2*nbNodes + 4*nbNodes); + vector quantities( 2 + nbNodes, 4 ); + quantities[0] = quantities[1] = nbNodes; + columns.resize( nbNodes + 1 ); + columns[ nbNodes ] = columns[ 0 ]; + for ( int i = 0; i < nbNodes; ++i ) { + nodes[ i ] = (*columns[ i ])[z-1]; // bottom + nodes[ i+nbNodes ] = (*columns[ i ])[z ]; // top + // side + int di = 2*nbNodes + 4*i - 1; + nodes[ di ] = (*columns[i ])[z-1]; + nodes[ di+1 ] = (*columns[i+1])[z-1]; + nodes[ di+2 ] = (*columns[i+1])[z ]; + nodes[ di+3 ] = (*columns[i ])[z ]; + } + vol = meshDS->AddPolyhedralVolume( nodes, quantities ); + } + if ( vol && shapeID > 0 ) + meshDS->SetMeshElementOnShape( vol, shapeID ); + } +} + +//================================================================================ +/*! + * \brief Find correspondence between bottom and top nodes + * If elements on the bottom and top faces are topologically different, + * and projection is possible and allowed, perform the projection + * \retval bool - is a success or not + */ +//================================================================================ + +bool StdMeshers_Prism_3D::assocOrProjBottom2Top() +{ + SMESH_subMesh * botSM = myBlock.SubMesh( ID_BOT_FACE ); + SMESH_subMesh * topSM = myBlock.SubMesh( ID_TOP_FACE ); + + SMESHDS_SubMesh * botSMDS = botSM->GetSubMeshDS(); + SMESHDS_SubMesh * topSMDS = topSM->GetSubMeshDS(); + + if ( !botSMDS || botSMDS->NbElements() == 0 ) + RETURN_BAD_RESULT("Empty horiz submesh"); + + bool needProject = false; + if ( !topSMDS || + botSMDS->NbElements() != topSMDS->NbElements() || + botSMDS->NbNodes() != topSMDS->NbNodes()) + { + if ( myBlock.HasNotQuadElemOnTop() ) + RETURN_BAD_RESULT("Different triangles on 2 sides"); + needProject = true; + } + + if ( 0/*needProject && !myProjectTriangles*/ ) + RETURN_BAD_RESULT("Need to project but not allowed"); + + if ( needProject ) + { + return projectBottomToTop(); + } + + TopoDS_Face botFace = TopoDS::Face( myBlock.Shape( ID_BOT_FACE )); + TopoDS_Face topFace = TopoDS::Face( myBlock.Shape( ID_TOP_FACE )); + // associate top and bottom faces + TAssocTool::TShapeShapeMap shape2ShapeMap; + if ( !TAssocTool::FindSubShapeAssociation( botFace, myBlock.Mesh(), + topFace, myBlock.Mesh(), + shape2ShapeMap) ) + RETURN_BAD_RESULT("FindSubShapeAssociation failed"); + + // Find matching nodes of in and out faces + TNodeNodeMap n2nMap; + if ( ! TAssocTool::FindMatchingNodesOnFaces( botFace, myBlock.Mesh(), + topFace, myBlock.Mesh(), + shape2ShapeMap, n2nMap )) + RETURN_BAD_RESULT("Different mesh on top and bottom faces"); + + // Fill myBotToColumnMap + + int zSize = myBlock.VerticalSize(); + TNodeNodeMap::iterator bN_tN = n2nMap.begin(); + for ( ; bN_tN != n2nMap.end(); ++bN_tN ) + { + const SMDS_MeshNode* botNode = bN_tN->first; + const SMDS_MeshNode* topNode = bN_tN->second; + if ( botNode->GetPosition()->GetTypeOfPosition() != SMDS_TOP_FACE ) + continue; // wall columns are contained in myBlock + // compute bottom node params + TNode bN( botNode ); + if ( !myBlock.ComputeParameters( bN.GetCoords(), bN.ChangeParams(), ID_BOT_FACE )) + RETURN_BAD_RESULT("ComputeParameters() on the bottom face failed"); + // create node column + TNode2ColumnMap::iterator bN_col = + myBotToColumnMap.insert( make_pair ( bN, TNodeColumn() )).first; + TNodeColumn & column = bN_col->second; + column.resize( zSize ); + column.front() = botNode; + column.back() = topNode; + } + return true; +} + +//================================================================================ +/*! + * \brief Remove quadrangles from the top face and + * create triangles there by projection from the bottom + * \retval bool - a success or not + */ +//================================================================================ + +bool StdMeshers_Prism_3D::projectBottomToTop() +{ + SMESH_subMesh * botSM = myBlock.SubMesh( ID_BOT_FACE ); + SMESH_subMesh * topSM = myBlock.SubMesh( ID_TOP_FACE ); + + SMESHDS_SubMesh * botSMDS = botSM->GetSubMeshDS(); + SMESHDS_SubMesh * topSMDS = topSM->GetSubMeshDS(); + + if ( topSMDS ) + topSM->ComputeStateEngine( SMESH_subMesh::CLEAN ); + + SMESHDS_Mesh* meshDS = myBlock.MeshDS(); + int shapeID = myHelper->GetSubShapeID(); + int topFaceID = meshDS->ShapeToIndex( topSM->GetSubShape() ); + + // Fill myBotToColumnMap + + int zSize = myBlock.VerticalSize(); + SMDS_NodeIteratorPtr nIt = botSMDS->GetNodes(); + while ( nIt->more() ) + { + const SMDS_MeshNode* botNode = nIt->next(); + if ( botNode->GetPosition()->GetTypeOfPosition() != SMDS_TOP_FACE ) + continue; // strange + // compute bottom node params + TNode bN( botNode ); + if ( !myBlock.ComputeParameters( bN.GetCoords(), bN.ChangeParams(), ID_BOT_FACE )) + RETURN_BAD_RESULT("ComputeParameters() on the bottom face failed"); + // compute top node coords + gp_XYZ topXYZ; gp_XY topUV; + if ( !myBlock.FacePoint( ID_TOP_FACE, bN.GetParams(), topXYZ ) || + !myBlock.FaceUV ( ID_TOP_FACE, bN.GetParams(), topUV )) + RETURN_BAD_RESULT("SMESH_Block::FacePoint() on the top face failed"); + SMDS_MeshNode * topNode = meshDS->AddNode( topXYZ.X(),topXYZ.Y(),topXYZ.Z() ); + meshDS->SetNodeOnFace( topNode, topFaceID, topUV.X(), topUV.Y() ); + // create node column + TNode2ColumnMap::iterator bN_col = + myBotToColumnMap.insert( make_pair ( bN, TNodeColumn() )).first; + TNodeColumn & column = bN_col->second; + column.resize( zSize ); + column.front() = botNode; + column.back() = topNode; + } + + // Create top faces + + // loop on bottom mesh faces + SMDS_ElemIteratorPtr faceIt = botSMDS->GetElements(); + while ( faceIt->more() ) + { + const SMDS_MeshElement* face = faceIt->next(); + if ( !face || face->GetType() != SMDSAbs_Face ) + continue; + int nbNodes = face->NbNodes(); + if ( face->IsQuadratic() ) + nbNodes /= 2; + + // find top node in columns for each bottom node + vector< const SMDS_MeshNode* > nodes( nbNodes ); + for ( int i = 0; i < nbNodes; ++i ) + { + const SMDS_MeshNode* n = face->GetNode( nbNodes - i - 1 ); + if ( n->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE ) { + TNode2ColumnMap::iterator bot_column = myBotToColumnMap.find( n ); + if ( bot_column == myBotToColumnMap.end() ) + RETURN_BAD_RESULT(" node column for a node not found"); + nodes[ i ] = bot_column->second.back(); + } + else { + const TNodeColumn* column = myBlock.GetNodeColumn( n ); + if ( !column ) + RETURN_BAD_RESULT(" node column not found for a node " << n->GetID() ); + nodes[ i ] = column->back(); + } + } + // create a face, with reversed orientation + SMDS_MeshElement* newFace = 0; + switch ( nbNodes ) { + + case 3: { + newFace = myHelper->AddFace(nodes[0], nodes[1], nodes[2]); + break; + } + case 4: { + newFace = myHelper->AddFace( nodes[0], nodes[1], nodes[2], nodes[3] ); + break; + } + default: + newFace = meshDS->AddPolygonalFace( nodes ); + } + if ( newFace && shapeID > 0 ) + meshDS->SetMeshElementOnShape( newFace, shapeID ); + } + + return true; +} + +//================================================================================ +/*! + * \brief Set projection coordinates of a node to a face and it's subshapes + * \param faceID - the face given by in-block ID + * \param params - node normalized parameters + * \retval bool - is a success + */ +//================================================================================ + +bool StdMeshers_Prism_3D::setFaceAndEdgesXYZ( const int faceID, const gp_XYZ& params, int z ) +{ + // find base and top edges of the face + enum { BASE = 0, TOP, LEFT, RIGHT }; + vector< int > edgeVec; // 0-base, 1-top + SMESH_Block::GetFaceEdgesIDs( faceID, edgeVec ); + + myBlock.EdgePoint( edgeVec[ BASE ], params, myShapeXYZ[ edgeVec[ BASE ]]); + myBlock.EdgePoint( edgeVec[ TOP ], params, myShapeXYZ[ edgeVec[ TOP ]]); + + SHOWYXZ("\nparams ", params); + SHOWYXZ("TOP is "< sideFaces( NB_WALL_FACES, 0 ); + vector< pair< double, double> > params ( NB_WALL_FACES ); + mySide = new TSideFace( sideFaces, params ); + + myHelper = helper; + SMESHDS_Mesh* meshDS = myHelper->GetMesh()->GetMeshDS(); + + int wallFaceIds[ NB_WALL_FACES ] = { // to walk around a block + SMESH_Block::ID_Fx0z, SMESH_Block::ID_F1yz, + SMESH_Block::ID_Fx1z, SMESH_Block::ID_F0yz + }; + SMESH_Block::init(); + + // ------------------------------------------------------------- + // Look for top and bottom faces: not quadrangle ones or meshed + // with not quadrangle elements + // ------------------------------------------------------------- + + list< SMESH_subMesh* > notQuadGeomSubMesh; + list< SMESH_subMesh* > notQuadElemSubMesh; + int nbFaces = 0; + // + SMESH_subMesh* mainSubMesh = myHelper->GetMesh()->GetSubMeshContaining( shape3D ); + if ( !mainSubMesh ) RETURN_BAD_RESULT("Null submesh of shape3D"); + // + const map< int, SMESH_subMesh * >& subSM = mainSubMesh->DependsOn(); + map< int, SMESH_subMesh * >::const_iterator i_subSM = subSM.begin(); + for ( ; i_subSM != subSM.end(); ++i_subSM ) + { + SMESH_subMesh* sm = i_subSM->second; + const TopoDS_Shape& face = sm->GetSubShape(); + if ( face.ShapeType() != TopAbs_FACE ) + continue; + nbFaces++; + + // is quadrangle face? + if ( TAssocTool::Count( face, TopAbs_EDGE, 0 ) != 4 || + TAssocTool::Count( face, TopAbs_WIRE, 0 ) != 1 ) + notQuadGeomSubMesh.push_back( sm ); + + // count not quadrangle mesh elements + if ( SMESHDS_SubMesh* smDS = sm->GetSubMeshDS() ) { + SMDS_ElemIteratorPtr eIt = smDS->GetElements(); + bool hasNotQuad = false; + while ( eIt->more() && !hasNotQuad ) { + const SMDS_MeshElement* elem = eIt->next(); + if ( elem->GetType() == SMDSAbs_Face ) { + int nbNodes = elem->NbNodes(); + if ( elem->IsQuadratic() ) + nbNodes /= 2; + hasNotQuad = ( nbNodes != 4 ); + } + } + if ( hasNotQuad ) + notQuadElemSubMesh.push_back( sm ); + } + else { + RETURN_BAD_RESULT("not meshed face"); + } + } + + // ---------------------------------------------------------------------- + // Analyse faces mesh and topology: choose the bottom submesh. + // If there are not quadrangle geom faces, they are top and bottom ones. + // Not quadrangle geom faces must be only on top and bottom. + // ---------------------------------------------------------------------- + + SMESH_subMesh * botSM = 0; + SMESH_subMesh * topSM = 0; + + int nbNotQuad = notQuadGeomSubMesh.size(); + int nbNotQuadMeshed = notQuadElemSubMesh.size(); + bool hasNotQuad = ( nbNotQuad || nbNotQuadMeshed ); + + // detect bad cases + if ( nbNotQuad > 0 && nbNotQuad != 2 ) + RETURN_BAD_RESULT("Wrong shape geometry"); + if ( nbNotQuadMeshed > 2 ) + RETURN_BAD_RESULT("More then 2 faces meshed with not quadrangle elements"); + + // get found submeshes + if ( hasNotQuad ) + { + if ( nbNotQuadMeshed > 0 ) botSM = notQuadElemSubMesh.front(); + else botSM = notQuadGeomSubMesh.front(); + if ( nbNotQuadMeshed > 1 ) topSM = notQuadElemSubMesh.back(); + else if ( nbNotQuad > 1 ) topSM = notQuadGeomSubMesh.back(); + } + // detect other bad cases + if ( nbNotQuad == 2 && nbNotQuadMeshed > 0 ) { + bool ok = false; + if ( nbNotQuadMeshed == 1 ) + ok = ( find( notQuadGeomSubMesh.begin(), + notQuadGeomSubMesh.end(), botSM ) != notQuadGeomSubMesh.end() ); + else + ok = ( notQuadGeomSubMesh == notQuadElemSubMesh ); + if ( !ok ) + RETURN_BAD_RESULT("Side face meshed with not quadrangle elements"); + } + + myNotQuadOnTop = ( nbNotQuadMeshed > 1 ); + + // ---------------------------------------------------------- + + if ( nbNotQuad == 0 ) // Standard block of 6 quadrangle faces ? + { + // SMESH_Block will perform geometry analysis, we need just to find 2 + // connected vertices on top and bottom + + TopoDS_Vertex Vbot, Vtop; + if ( nbNotQuadMeshed > 0 ) // Look for vertices + { + TopTools_IndexedMapOfShape edgeMap; + TopExp::MapShapes( botSM->GetSubShape(), TopAbs_EDGE, edgeMap ); + // vertex 1 is any vertex of the bottom face + Vbot = TopExp::FirstVertex( TopoDS::Edge( edgeMap( 1 ))); + // vertex 2 is end vertex of edge sharing Vbot and not belonging to the bottom face + TopTools_ListIteratorOfListOfShape ancestIt = Mesh()->GetAncestors( Vbot ); + for ( ; Vtop.IsNull() && ancestIt.More(); ancestIt.Next() ) + { + const TopoDS_Shape & ancestor = ancestIt.Value(); + if ( ancestor.ShapeType() == TopAbs_EDGE && !edgeMap.FindIndex( ancestor )) + { + Vtop = TopExp::LastVertex( TopoDS::Edge( ancestor )); + if ( Vbot.IsSame ( Vtop )) + Vtop = TopExp::FirstVertex( TopoDS::Edge( ancestor )); + } + } + } + // get shell from shape3D + TopoDS_Shell shell; + TopExp_Explorer exp( shape3D, TopAbs_SHELL ); + int nbShell = 0; + for ( ; exp.More(); exp.Next(), ++nbShell ) + shell = TopoDS::Shell( exp.Current() ); +// if ( nbShell != 1 ) +// RETURN_BAD_RESULT("There must be 1 shell in the block"); + + // Load geometry in SMESH_Block + myShapeIDMap.Clear(); + if ( !SMESH_Block::FindBlockShapes( shell, Vbot, Vtop, myShapeIDMap )) { + if ( !hasNotQuad ) + RETURN_BAD_RESULT("Can not detect top and bottom"); + } + else { + if ( !botSM ) botSM = Mesh()->GetSubMeshContaining( myShapeIDMap( ID_BOT_FACE )); + if ( !topSM ) topSM = Mesh()->GetSubMeshContaining( myShapeIDMap( ID_TOP_FACE )); + } + + } // end Standard block of 6 quadrangle faces + // -------------------------------------------------------- + + // Here the top and bottom faces are found + if ( nbNotQuadMeshed == 2 ) // roughly check correspondence of horiz meshes + { +// SMESHDS_SubMesh* topSMDS = topSM->GetSubMeshDS(); +// SMESHDS_SubMesh* botSMDS = botSM->GetSubMeshDS(); +// if ( topSMDS->NbNodes() != botSMDS->NbNodes() || +// topSMDS->NbElements() != botSMDS->NbElements() ) +// RETURN_BAD_RESULT("Top mesh doesn't correspond to bottom one"); + } + + // --------------------------------------------------------- + // If there are not quadrangle geom faces, we emulate + // a block of 6 quadrangle faces. + // Load SMESH_Block with faces and edges geometry + // --------------------------------------------------------- + + + // find vertex 000 - the one with smallest coordinates (for easy DEBUG :-) + TopoDS_Vertex V000; + double minVal = DBL_MAX, minX, val; + for ( TopExp_Explorer exp( botSM->GetSubShape(), TopAbs_VERTEX ); + exp.More(); exp.Next() ) + { + const TopoDS_Vertex& v = TopoDS::Vertex( exp.Current() ); + gp_Pnt P = BRep_Tool::Pnt( v ); + val = P.X() + P.Y() + P.Z(); + if ( val < minVal || ( val == minVal && P.X() < minX )) { + V000 = v; + minVal = val; + minX = P.X(); + } + } + + // Get ordered bottom edges + list< TopoDS_Edge > orderedEdges; + list< int > nbVertexInWires; + SMESH_Block::GetOrderedEdges( TopoDS::Face( botSM->GetSubShape().Reversed() ), + V000, orderedEdges, nbVertexInWires ); +// if ( nbVertexInWires.size() != 1 ) +// RETURN_BAD_RESULT("Wrong prism geometry"); + + // Get Wall faces corresponding to the ordered bottom edges + list< TopoDS_Face > wallFaces; + if ( !GetWallFaces( Mesh(), shape3D, botSM->GetSubShape(), orderedEdges, wallFaces)) + RETURN_BAD_RESULT("GetWallFaces() failed"); + + // Find columns of wall nodes and calculate edges' lengths + // -------------------------------------------------------- + + myParam2ColumnMaps.clear(); + myParam2ColumnMaps.resize( orderedEdges.size() ); // total nb edges + + int iE, nbEdges = nbVertexInWires.front(); // nb outer edges + vector< double > edgeLength( nbEdges ); + map< double, int > len2edgeMap; + + list< TopoDS_Edge >::iterator edgeIt = orderedEdges.begin(); + list< TopoDS_Face >::iterator faceIt = wallFaces.begin(); + for ( iE = 0; iE < nbEdges; ++edgeIt, ++faceIt ) + { + TParam2ColumnMap & faceColumns = myParam2ColumnMaps[ iE ]; + if ( !myHelper->LoadNodeColumns( faceColumns, *faceIt, *edgeIt, meshDS )) + RETURN_BAD_RESULT("SMESH_MesherHelper::LoadNodeColumns() failed"); + + SHOWYXZ("\np1 F "<second.front() )); + SHOWYXZ("p2 F "<second.front() )); + SHOWYXZ("V First "<MeshElements( *edgeIt); + if ( !smDS ) + RETURN_BAD_RESULT("Null submesh on a bottom edge"); + // assure length uniqueness + edgeLength[ iE ] *= smDS->NbNodes() + edgeLength[ iE ] / ( 1000 + iE ); + len2edgeMap[ edgeLength[ iE ]] = iE; + } + ++iE; + } + // Load columns of internal edges (forming holes) + // and fill map ShapeIndex to TParam2ColumnMap for them + for ( ; edgeIt != orderedEdges.end() ; ++edgeIt, ++faceIt ) + { + TParam2ColumnMap & faceColumns = myParam2ColumnMaps[ iE ]; + if ( !myHelper->LoadNodeColumns( faceColumns, *faceIt, *edgeIt, meshDS )) + RETURN_BAD_RESULT("SMESH_MesherHelper::LoadNodeColumns() failed"); + // edge columns + int id = MeshDS()->ShapeToIndex( *edgeIt ); + bool isForward = true; // meaningless for intenal wires + myShapeIndex2ColumnMap[ id ] = make_pair( & faceColumns, isForward ); + // columns for vertices + // 1 + const SMDS_MeshNode* n0 = faceColumns.begin()->second.front(); + id = n0->GetPosition()->GetShapeId(); + myShapeIndex2ColumnMap[ id ] = make_pair( & faceColumns, isForward ); + // 2 + const SMDS_MeshNode* n1 = faceColumns.rbegin()->second.front(); + id = n1->GetPosition()->GetShapeId(); + myShapeIndex2ColumnMap[ id ] = make_pair( & faceColumns, isForward ); +// SHOWYXZ("\np1 F "<second.front() )); +// SHOWYXZ("p2 F "<second.front() )); +// SHOWYXZ("V First "< iE2nbSplit; + if ( nbEdges != NB_WALL_FACES ) // define how to split + { + if ( len2edgeMap.size() != nbEdges ) + RETURN_BAD_RESULT("Uniqueness of edge lengths not assured"); + map< double, int >::reverse_iterator maxLen_i = len2edgeMap.rbegin(); + map< double, int >::reverse_iterator midLen_i = ++len2edgeMap.rbegin(); + double maxLen = maxLen_i->first; + double midLen = ( len2edgeMap.size() == 1 ) ? 0 : midLen_i->first; + switch ( nbEdges ) { + case 1: // 0-th edge is split into 4 parts + iE2nbSplit.insert( make_pair( 0, 4 )); break; + case 2: // either the longest edge is split into 3 parts, or both edges into halves + if ( maxLen / 3 > midLen / 2 ) { + iE2nbSplit.insert( make_pair( maxLen_i->second, 3 )); + } + else { + iE2nbSplit.insert( make_pair( maxLen_i->second, 2 )); + iE2nbSplit.insert( make_pair( midLen_i->second, 2 )); + } + break; + case 3: + // split longest into halves + iE2nbSplit.insert( make_pair( maxLen_i->second, 2 )); + } + } + // Create TSideFace's + faceIt = wallFaces.begin(); + edgeIt = orderedEdges.begin(); + int iSide = 0; + for ( iE = 0; iE < nbEdges; ++edgeIt, ++faceIt ) + { + // split? + map< int, int >::iterator i_nb = iE2nbSplit.find( iE ); + if ( i_nb != iE2nbSplit.end() ) { + // split! + int nbSplit = i_nb->second; + vector< double > params; + splitParams( nbSplit, &myParam2ColumnMaps[ iE ], params ); + bool isForward = ( edgeIt->Orientation() == TopAbs_FORWARD ); + for ( int i = 0; i < nbSplit; ++i ) { + double f = ( isForward ? params[ i ] : params[ nbSplit - i-1 ]); + double l = ( isForward ? params[ i+1 ] : params[ nbSplit - i ]); + TSideFace* comp = new TSideFace( myHelper, wallFaceIds[ iSide ], + *faceIt, *edgeIt, + &myParam2ColumnMaps[ iE ], f, l ); + mySide->SetComponent( iSide++, comp ); + } + } + else { + TSideFace* comp = new TSideFace( myHelper, wallFaceIds[ iSide ], + *faceIt, *edgeIt, + &myParam2ColumnMaps[ iE ]); + mySide->SetComponent( iSide++, comp ); + } + ++iE; + } + } + else { // **************************** Unite faces + + // unite first faces + int nbExraFaces = nbEdges - 3; + int iSide = 0, iE; + double u0 = 0, sumLen = 0; + for ( iE = 0; iE < nbExraFaces; ++iE ) + sumLen += edgeLength[ iE ]; + + vector< TSideFace* > components( nbExraFaces ); + vector< pair< double, double> > params( nbExraFaces ); + faceIt = wallFaces.begin(); + edgeIt = orderedEdges.begin(); + for ( iE = 0; iE < nbExraFaces; ++edgeIt, ++faceIt ) + { + components[ iE ] = new TSideFace( myHelper, wallFaceIds[ iSide ], + *faceIt, *edgeIt, + &myParam2ColumnMaps[ iE ]); + double u1 = u0 + edgeLength[ iE ] / sumLen; + params[ iE ] = make_pair( u0 , u1 ); + u0 = u1; + ++iE; + } + mySide->SetComponent( iSide++, new TSideFace( components, params )); + + // fill the rest faces + for ( ; iE < nbEdges; ++faceIt, ++edgeIt ) + { + TSideFace* comp = new TSideFace( myHelper, wallFaceIds[ iSide ], + *faceIt, *edgeIt, + &myParam2ColumnMaps[ iE ]); + mySide->SetComponent( iSide++, comp ); + ++iE; + } + } + + + // Fill geometry fields of SMESH_Block + // ------------------------------------ + + TopoDS_Face botF = TopoDS::Face( botSM->GetSubShape() ); + TopoDS_Face topF = TopoDS::Face( topSM->GetSubShape() ); + + vector< int > botEdgeIdVec; + SMESH_Block::GetFaceEdgesIDs( ID_BOT_FACE, botEdgeIdVec ); + + bool isForward[NB_WALL_FACES] = { true, true, true, true }; + Adaptor2d_Curve2d* botPcurves[NB_WALL_FACES]; + Adaptor2d_Curve2d* topPcurves[NB_WALL_FACES]; + + for ( int iF = 0; iF < NB_WALL_FACES; ++iF ) + { + TSideFace * sideFace = mySide->GetComponent( iF ); + if ( !sideFace ) + RETURN_BAD_RESULT("NULL TSideFace"); + int fID = sideFace->FaceID(); + + // fill myShapeIDMap + if ( sideFace->InsertSubShapes( myShapeIDMap ) != 8 && + !sideFace->IsComplex()) + MESSAGE( ": Warning : InsertSubShapes() < 8 on side " << iF ); + + // side faces geometry + Adaptor2d_Curve2d* pcurves[NB_WALL_FACES]; + if ( !sideFace->GetPCurves( pcurves )) + RETURN_BAD_RESULT("TSideFace::GetPCurves() failed"); + + SMESH_Block::TFace& tFace = myFace[ fID - ID_FirstF ]; + tFace.Set( fID, sideFace->Surface(), pcurves, isForward ); + + SHOWYXZ( endl<<"F "<< iF << " id " << fID << " FRW " << sideFace->IsForward(), ); + // edges 3D geometry + vector< int > edgeIdVec; + SMESH_Block::GetFaceEdgesIDs( fID, edgeIdVec ); + for ( int isMax = 0; isMax < 2; ++isMax ) { + { + int eID = edgeIdVec[ isMax ]; + SMESH_Block::TEdge& tEdge = myEdge[ eID - ID_FirstE ]; + tEdge.Set( eID, sideFace->HorizCurve(isMax), true); + SHOWYXZ(eID<<" HOR"<HorizCurve(isMax)->Value(0)); + SHOWYXZ(eID<<" HOR"<HorizCurve(isMax)->Value(1)); + } + { + int eID = edgeIdVec[ isMax+2 ]; + SMESH_Block::TEdge& tEdge = myEdge[ eID - ID_FirstE ]; + tEdge.Set( eID, sideFace->VertiCurve(isMax), true); + SHOWYXZ(eID<<" VER"<VertiCurve(isMax)->Value(0)); + SHOWYXZ(eID<<" VER"<VertiCurve(isMax)->Value(1)); + + // corner points + vector< int > vertexIdVec; + SMESH_Block::GetEdgeVertexIDs( eID, vertexIdVec ); + myPnt[ vertexIdVec[0] - ID_FirstV ] = tEdge.GetCurve()->Value(0).XYZ(); + myPnt[ vertexIdVec[1] - ID_FirstV ] = tEdge.GetCurve()->Value(1).XYZ(); + } + } + // pcurves on horizontal faces + for ( iE = 0; iE < NB_WALL_FACES; ++iE ) { + if ( edgeIdVec[ BOTTOM_EDGE ] == botEdgeIdVec[ iE ] ) { + botPcurves[ iE ] = sideFace->HorizPCurve( false, botF ); + topPcurves[ iE ] = sideFace->HorizPCurve( true, topF ); + break; + } + } + } + // horizontal faces geometry + { + SMESH_Block::TFace& tFace = myFace[ ID_BOT_FACE - ID_FirstF ]; + tFace.Set( ID_BOT_FACE, new BRepAdaptor_Surface( botF ), botPcurves, isForward ); + SMESH_Block::Insert( botF, ID_BOT_FACE, myShapeIDMap ); + } + { + SMESH_Block::TFace& tFace = myFace[ ID_TOP_FACE - ID_FirstF ]; + tFace.Set( ID_TOP_FACE, new BRepAdaptor_Surface( topF ), topPcurves, isForward ); + SMESH_Block::Insert( topF, ID_TOP_FACE, myShapeIDMap ); + } + + // Fill map ShapeIndex to TParam2ColumnMap + // ---------------------------------------- + + list< TSideFace* > fList; + list< TSideFace* >::iterator fListIt; + fList.push_back( mySide ); + for ( fListIt = fList.begin(); fListIt != fList.end(); ++fListIt) + { + int nb = (*fListIt)->NbComponents(); + for ( int i = 0; i < nb; ++i ) { + if ( TSideFace* comp = (*fListIt)->GetComponent( i )) + fList.push_back( comp ); + } + if ( TParam2ColumnMap* cols = (*fListIt)->GetColumns()) { + // columns for a base edge + int id = MeshDS()->ShapeToIndex( (*fListIt)->BaseEdge() ); + bool isForward = (*fListIt)->IsForward(); + myShapeIndex2ColumnMap[ id ] = make_pair( cols, isForward ); + + // columns for vertices + const SMDS_MeshNode* n0 = cols->begin()->second.front(); + id = n0->GetPosition()->GetShapeId(); + myShapeIndex2ColumnMap[ id ] = make_pair( cols, isForward ); + + const SMDS_MeshNode* n1 = cols->rbegin()->second.front(); + id = n1->GetPosition()->GetShapeId(); + myShapeIndex2ColumnMap[ id ] = make_pair( cols, !isForward ); + } + } + +// gp_XYZ testPar(0.25, 0.25, 0), testCoord; +// if ( !FacePoint( ID_BOT_FACE, testPar, testCoord )) +// RETURN_BAD_RESULT("TEST FacePoint() FAILED"); +// SHOWYXZ("IN TEST PARAM" , testPar); +// SHOWYXZ("OUT TEST CORD" , testCoord); +// if ( !ComputeParameters( testCoord, testPar , ID_BOT_FACE)) +// RETURN_BAD_RESULT("TEST ComputeParameters() FAILED"); +// SHOWYXZ("OUT TEST PARAM" , testPar); + + return true; +} + +//================================================================================ +/*! + * \brief Return pointer to column of nodes + * \param node - bottom node from which the returned column goes up + * \retval const TNodeColumn* - the found column + */ +//================================================================================ + +const TNodeColumn* StdMeshers_PrismAsBlock::GetNodeColumn(const SMDS_MeshNode* node) const +{ + int sID = node->GetPosition()->GetShapeId(); + + map >::const_iterator col_frw = + myShapeIndex2ColumnMap.find( sID ); + if ( col_frw != myShapeIndex2ColumnMap.end() ) { + const TParam2ColumnMap* cols = col_frw->second.first; + TParam2ColumnIt u_col = cols->begin(); + for ( ; u_col != cols->end(); ++u_col ) + if ( u_col->second[ 0 ] == node ) + return & u_col->second; + } + return 0; +} + +//================================================================================ +/*! + * \brief Check curve orientation of a bootom edge + * \param meshDS - mesh DS + * \param columnsMap - node columns map of side face + * \param bottomEdge - the bootom edge + * \param sideFaceID - side face in-block ID + * \retval bool - true if orientation coinside with in-block froward orientation + */ +//================================================================================ + +bool StdMeshers_PrismAsBlock::IsForwardEdge(SMESHDS_Mesh* meshDS, + const TParam2ColumnMap& columnsMap, + const TopoDS_Edge & bottomEdge, + const int sideFaceID) +{ + bool isForward = false; + if ( TAssocTool::IsClosedEdge( bottomEdge )) + { + isForward = ( bottomEdge.Orientation() == TopAbs_FORWARD ); + } + else + { + const TNodeColumn& firstCol = columnsMap.begin()->second; + const SMDS_MeshNode* bottomNode = firstCol[0]; + TopoDS_Shape firstVertex = SMESH_MesherHelper::GetSubShapeByNode( bottomNode, meshDS ); + isForward = ( firstVertex.IsSame( TopExp::FirstVertex( bottomEdge, true ))); + } + // on 2 of 4 sides first vertex is end + if ( sideFaceID == ID_Fx1z || sideFaceID == ID_F0yz ) + isForward = !isForward; + return isForward; +} + +//================================================================================ + /*! + * \brief Find wall faces by bottom edges + * \param mesh - the mesh + * \param mainShape - the prism + * \param bottomFace - the bottom face + * \param bottomEdges - edges bounding the bottom face + * \param wallFaces - faces list to fill in + */ +//================================================================================ + +bool StdMeshers_PrismAsBlock::GetWallFaces( SMESH_Mesh* mesh, + const TopoDS_Shape & mainShape, + const TopoDS_Shape & bottomFace, + const std::list< TopoDS_Edge >& bottomEdges, + std::list< TopoDS_Face >& wallFaces) +{ + wallFaces.clear(); + + TopTools_IndexedMapOfShape faceMap; + TopExp::MapShapes( mainShape, TopAbs_FACE, faceMap ); + + list< TopoDS_Edge >::const_iterator edge = bottomEdges.begin(); + for ( ; edge != bottomEdges.end(); ++edge ) + { + TopTools_ListIteratorOfListOfShape ancestIt = mesh->GetAncestors( *edge ); + for ( ; ancestIt.More(); ancestIt.Next() ) + { + const TopoDS_Shape& ancestor = ancestIt.Value(); + if ( ancestor.ShapeType() == TopAbs_FACE && // face + !bottomFace.IsSame( ancestor ) && // not bottom + faceMap.FindIndex( ancestor )) // belongs to the prism + { + wallFaces.push_back( TopoDS::Face( ancestor )); + break; + } + } + } + return ( wallFaces.size() == bottomEdges.size() ); +} + +//================================================================================ +/*! + * \brief Constructor + * \param faceID - in-block ID + * \param face - geom face + * \param columnsMap - map of node columns + * \param first - first normalized param + * \param last - last normalized param + */ +//================================================================================ + +StdMeshers_PrismAsBlock::TSideFace::TSideFace(SMESH_MesherHelper* helper, + const int faceID, + const TopoDS_Face& face, + const TopoDS_Edge& baseEdge, + TParam2ColumnMap* columnsMap, + const double first, + const double last): + myID( faceID ), + myParamToColumnMap( columnsMap ), + myBaseEdge( baseEdge ), + myHelper( helper ) +{ + mySurface.Initialize( face ); + myParams.resize( 1 ); + myParams[ 0 ] = make_pair( first, last ); + myIsForward = StdMeshers_PrismAsBlock::IsForwardEdge( myHelper->GetMeshDS(), + *myParamToColumnMap, + myBaseEdge, myID ); +} + +//================================================================================ +/*! + * \brief Constructor of complex side face + */ +//================================================================================ + +StdMeshers_PrismAsBlock::TSideFace:: +TSideFace(const vector< TSideFace* >& components, + const vector< pair< double, double> > & params) + :myID( components[0] ? components[0]->myID : 0 ), + myParamToColumnMap( 0 ), + myParams( params ), + myIsForward( true ), + myComponents( components ), + myHelper( components[0] ? components[0]->myHelper : 0 ) +{} +//================================================================================ +/*! + * \brief Copy constructor + * \param other - other side + */ +//================================================================================ + +StdMeshers_PrismAsBlock::TSideFace::TSideFace( const TSideFace& other ) +{ + myID = other.myID; + mySurface = other.mySurface; + myBaseEdge = other.myBaseEdge; + myParams = other.myParams; + myIsForward = other.myIsForward; + myHelper = other.myHelper; + myParamToColumnMap = other.myParamToColumnMap; + + myComponents.resize( other.myComponents.size()); + for (int i = 0 ; i < myComponents.size(); ++i ) + myComponents[ i ] = new TSideFace( *other.myComponents[ i ]); +} + +//================================================================================ +/*! + * \brief Deletes myComponents + */ +//================================================================================ + +StdMeshers_PrismAsBlock::TSideFace::~TSideFace() +{ + for (int i = 0 ; i < myComponents.size(); ++i ) + if ( myComponents[ i ] ) + delete myComponents[ i ]; +} + +//================================================================================ +/*! + * \brief Return geometry of the vertical curve + * \param isMax - true means curve located closer to (1,1,1) block point + * \retval Adaptor3d_Curve* - curve adaptor + */ +//================================================================================ + +Adaptor3d_Curve* StdMeshers_PrismAsBlock::TSideFace::VertiCurve(const bool isMax) const +{ + if ( !myComponents.empty() ) { + if ( isMax ) + return myComponents.back()->VertiCurve(isMax); + else + return myComponents.front()->VertiCurve(isMax); + } + double f = myParams[0].first, l = myParams[0].second; + if ( !myIsForward ) std::swap( f, l ); + return new TVerticalEdgeAdaptor( myParamToColumnMap, isMax ? l : f ); +} + +//================================================================================ +/*! + * \brief Return geometry of the top or bottom curve + * \param isTop - + * \retval Adaptor3d_Curve* - + */ +//================================================================================ + +Adaptor3d_Curve* StdMeshers_PrismAsBlock::TSideFace::HorizCurve(const bool isTop) const +{ + return new THorizontalEdgeAdaptor( this, isTop ); +} + +//================================================================================ +/*! + * \brief Return pcurves + * \param pcurv - array of 4 pcurves + * \retval bool - is a success + */ +//================================================================================ + +bool StdMeshers_PrismAsBlock::TSideFace::GetPCurves(Adaptor2d_Curve2d* pcurv[4]) const +{ + int iEdge[ 4 ] = { BOTTOM_EDGE, TOP_EDGE, V0_EDGE, V1_EDGE }; + + for ( int i = 0 ; i < 4 ; ++i ) { + Handle(Geom2d_Line) line; + switch ( iEdge[ i ] ) { + case TOP_EDGE: + line = new Geom2d_Line( gp_Pnt2d( 0, 1 ), gp::DX2d() ); break; + case BOTTOM_EDGE: + line = new Geom2d_Line( gp::Origin2d(), gp::DX2d() ); break; + case V0_EDGE: + line = new Geom2d_Line( gp::Origin2d(), gp::DY2d() ); break; + case V1_EDGE: + line = new Geom2d_Line( gp_Pnt2d( 1, 0 ), gp::DY2d() ); break; + } + pcurv[ i ] = new Geom2dAdaptor_Curve( line, 0, 1 ); + } + return true; +} + +//================================================================================ +/*! + * \brief Returns geometry of pcurve on a horizontal face + * \param isTop - is top or bottom face + * \param horFace - a horizontal face + * \retval Adaptor2d_Curve2d* - curve adaptor + */ +//================================================================================ + +Adaptor2d_Curve2d* +StdMeshers_PrismAsBlock::TSideFace::HorizPCurve(const bool isTop, + const TopoDS_Face& horFace) const +{ + return new TPCurveOnHorFaceAdaptor( this, isTop, horFace ); +} + +//================================================================================ +/*! + * \brief Return a component corresponding to parameter + * \param U - parameter along a horizontal size + * \param localU - parameter along a horizontal size of a component + * \retval TSideFace* - found component + */ +//================================================================================ + +StdMeshers_PrismAsBlock::TSideFace* +StdMeshers_PrismAsBlock::TSideFace::GetComponent(const double U,double & localU) const +{ + localU = U; + if ( myComponents.empty() ) + return const_cast( this ); + + int i; + for ( i = 0; i < myComponents.size(); ++i ) + if ( U < myParams[ i ].second ) + break; + if ( i >= myComponents.size() ) + i = myComponents.size() - 1; + + double f = myParams[ i ].first, l = myParams[ i ].second; + localU = ( U - f ) / ( l - f ); + return myComponents[ i ]; +} + +//================================================================================ +/*! + * \brief Find node columns for a parameter + * \param U - parameter along a horizontal edge + * \param col1 - the 1st found column + * \param col2 - the 2nd found column + * \retval r - normalized position of U between the found columns + */ +//================================================================================ + +double StdMeshers_PrismAsBlock::TSideFace::GetColumns(const double U, + TParam2ColumnIt & col1, + TParam2ColumnIt & col2) const +{ + double u = U, r = 0; + if ( !myComponents.empty() ) { + TSideFace * comp = GetComponent(U,u); + return comp->GetColumns( u, col1, col2 ); + } + + if ( !myIsForward ) + u = 1 - u; + double f = myParams[0].first, l = myParams[0].second; + u = f + u * ( l - f ); + + col1 = col2 = getColumn( myParamToColumnMap, u ); + if ( ++col2 == myParamToColumnMap->end() ) { + --col2; + r = 0.5; + } + else { +// if ( !myIsForward ) +// std::swap( col1, col2 ); + double uf = col1->first; + double ul = col2->first; + r = ( u - uf ) / ( ul - uf ); + } + return r; +} + +//================================================================================ +/*! + * \brief Return coordinates by normalized params + * \param U - horizontal param + * \param V - vertical param + * \retval gp_Pnt - result point + */ +//================================================================================ + +gp_Pnt StdMeshers_PrismAsBlock::TSideFace::Value(const Standard_Real U, + const Standard_Real V) const +{ + double u; + if ( !myComponents.empty() ) { + TSideFace * comp = GetComponent(U,u); + return comp->Value( u, V ); + } + + TParam2ColumnIt u_col1, u_col2; + double vR, hR = GetColumns( U, u_col1, u_col2 ); + + const SMDS_MeshNode* n1 = 0; + const SMDS_MeshNode* n2 = 0; + const SMDS_MeshNode* n3 = 0; + const SMDS_MeshNode* n4 = 0; + gp_XYZ pnt; + + vR = getRAndNodes( & u_col1->second, V, n1, n2 ); + vR = getRAndNodes( & u_col2->second, V, n3, n4 ); + + gp_XY uv1 = myHelper->GetNodeUV( mySurface.Face(), n1, n4); + gp_XY uv2 = myHelper->GetNodeUV( mySurface.Face(), n2, n3); + gp_XY uv12 = uv1 * ( 1 - vR ) + uv2 * vR; + + gp_XY uv3 = myHelper->GetNodeUV( mySurface.Face(), n3, n2); + gp_XY uv4 = myHelper->GetNodeUV( mySurface.Face(), n4, n1); + gp_XY uv34 = uv3 * ( 1 - vR ) + uv4 * vR; + + gp_XY uv = uv12 * ( 1 - hR ) + uv34 * hR; + + return mySurface.Value( uv.X(), uv.Y() ); +} + + +//================================================================================ +/*! + * \brief Return boundary edge + * \param edge - edge index + * \retval TopoDS_Edge - found edge + */ +//================================================================================ + +TopoDS_Edge StdMeshers_PrismAsBlock::TSideFace::GetEdge(const int iEdge) const +{ + if ( !myComponents.empty() ) { + switch ( iEdge ) { + case V0_EDGE : return myComponents.front()->GetEdge( iEdge ); + case V1_EDGE : return myComponents.back() ->GetEdge( iEdge ); + default: return TopoDS_Edge(); + } + } + TopoDS_Shape edge; + const SMDS_MeshNode* node = 0; + SMESHDS_Mesh * meshDS = myHelper->GetMesh()->GetMeshDS(); + TNodeColumn* column; + + switch ( iEdge ) { + case TOP_EDGE: + case BOTTOM_EDGE: + column = & (( ++myParamToColumnMap->begin())->second ); + node = ( iEdge == TOP_EDGE ) ? column->back() : column->front(); + edge = myHelper->GetSubShapeByNode ( node, meshDS ); + if ( edge.ShapeType() == TopAbs_VERTEX ) { + column = & ( myParamToColumnMap->begin()->second ); + node = ( iEdge == TOP_EDGE ) ? column->back() : column->front(); + } + break; + case V0_EDGE: + case V1_EDGE: { + bool back = ( iEdge == V1_EDGE ); + if ( !myIsForward ) back = !back; + if ( back ) + column = & ( myParamToColumnMap->rbegin()->second ); + else + column = & ( myParamToColumnMap->begin()->second ); + if ( column->size() > 0 ) + edge = myHelper->GetSubShapeByNode( (*column)[ 1 ], meshDS ); + if ( edge.IsNull() || edge.ShapeType() == TopAbs_VERTEX ) + node = column->front(); + break; + } + default:; + } + if ( !edge.IsNull() || edge.ShapeType() == TopAbs_EDGE ) + return TopoDS::Edge( edge ); + + // find edge by 2 vertices + TopoDS_Shape V1 = edge; + TopoDS_Shape V2 = myHelper->GetSubShapeByNode( node, meshDS ); + if ( V2.ShapeType() == TopAbs_VERTEX && !V2.IsSame( V1 )) + { + TopTools_ListIteratorOfListOfShape ancestIt = + myHelper->GetMesh()->GetAncestors( V1 ); + for ( ; ancestIt.More(); ancestIt.Next() ) + { + const TopoDS_Shape & ancestor = ancestIt.Value(); + if ( ancestor.ShapeType() == TopAbs_EDGE ) + for ( TopExp_Explorer e( ancestor, TopAbs_VERTEX ); e.More(); e.Next() ) + if ( V2.IsSame( e.Current() )) + return TopoDS::Edge( ancestor ); + } + } + return TopoDS_Edge(); +} + +//================================================================================ +/*! + * \brief Fill block subshapes + * \param shapeMap - map to fill in + * \retval int - nb inserted subshapes + */ +//================================================================================ + +int StdMeshers_PrismAsBlock::TSideFace::InsertSubShapes(TBlockShapes& shapeMap) const +{ + int nbInserted = 0; + + // Insert edges + vector< int > edgeIdVec; + SMESH_Block::GetFaceEdgesIDs( myID, edgeIdVec ); + + for ( int i = BOTTOM_EDGE; i <=V1_EDGE ; ++i ) { + TopoDS_Edge e = GetEdge( i ); + if ( !e.IsNull() ) { + nbInserted += SMESH_Block::Insert( e, edgeIdVec[ i ], shapeMap); + } + } + + // Insert corner vertices + + TParam2ColumnIt col1, col2 ; + vector< int > vertIdVec; + + // from V0 column + SMESH_Block::GetEdgeVertexIDs( edgeIdVec[ V0_EDGE ], vertIdVec); + GetColumns(0, col1, col2 ); + const SMDS_MeshNode* node0 = col1->second.front(); + const SMDS_MeshNode* node1 = col1->second.back(); + TopoDS_Shape v0 = myHelper->GetSubShapeByNode( node0, myHelper->GetMeshDS()); + TopoDS_Shape v1 = myHelper->GetSubShapeByNode( node1, myHelper->GetMeshDS()); + if ( v0.ShapeType() == TopAbs_VERTEX ) { + nbInserted += SMESH_Block::Insert( v0, vertIdVec[ 0 ], shapeMap); + } + if ( v1.ShapeType() == TopAbs_VERTEX ) { + nbInserted += SMESH_Block::Insert( v1, vertIdVec[ 1 ], shapeMap); + } + + // from V1 column + SMESH_Block::GetEdgeVertexIDs( edgeIdVec[ V1_EDGE ], vertIdVec); + GetColumns(1, col1, col2 ); + node0 = col2->second.front(); + node1 = col2->second.back(); + v0 = myHelper->GetSubShapeByNode( node0, myHelper->GetMeshDS()); + v1 = myHelper->GetSubShapeByNode( node1, myHelper->GetMeshDS()); + if ( v0.ShapeType() == TopAbs_VERTEX ) { + nbInserted += SMESH_Block::Insert( v0, vertIdVec[ 0 ], shapeMap); + } + if ( v1.ShapeType() == TopAbs_VERTEX ) { + nbInserted += SMESH_Block::Insert( v1, vertIdVec[ 1 ], shapeMap); + } + +// TopoDS_Vertex V0, V1, Vcom; +// TopExp::Vertices( myBaseEdge, V0, V1, true ); +// if ( !myIsForward ) std::swap( V0, V1 ); + +// // bottom vertex IDs +// SMESH_Block::GetEdgeVertexIDs( edgeIdVec[ _u0 ], vertIdVec); +// SMESH_Block::Insert( V0, vertIdVec[ 0 ], shapeMap); +// SMESH_Block::Insert( V1, vertIdVec[ 1 ], shapeMap); + +// TopoDS_Edge sideEdge = GetEdge( V0_EDGE ); +// if ( sideEdge.IsNull() || !TopExp::CommonVertex( botEdge, sideEdge, Vcom )) +// return false; + +// // insert one side edge +// int edgeID; +// if ( Vcom.IsSame( V0 )) edgeID = edgeIdVec[ _v0 ]; +// else edgeID = edgeIdVec[ _v1 ]; +// SMESH_Block::Insert( sideEdge, edgeID, shapeMap); + +// // top vertex of the side edge +// SMESH_Block::GetEdgeVertexIDs( edgeID, vertIdVec); +// TopoDS_Vertex Vtop = TopExp::FirstVertex( sideEdge ); +// if ( Vcom.IsSame( Vtop )) +// Vtop = TopExp::LastVertex( sideEdge ); +// SMESH_Block::Insert( Vtop, vertIdVec[ 1 ], shapeMap); + +// // other side edge +// sideEdge = GetEdge( V1_EDGE ); +// if ( sideEdge.IsNull() ) +// return false; +// if ( edgeID = edgeIdVec[ _v1 ]) edgeID = edgeIdVec[ _v0 ]; +// else edgeID = edgeIdVec[ _v1 ]; +// SMESH_Block::Insert( sideEdge, edgeID, shapeMap); + +// // top edge +// TopoDS_Edge topEdge = GetEdge( TOP_EDGE ); +// SMESH_Block::Insert( topEdge, edgeIdVec[ _u1 ], shapeMap); + +// // top vertex of the other side edge +// if ( !TopExp::CommonVertex( topEdge, sideEdge, Vcom )) +// return false; +// SMESH_Block::GetEdgeVertexIDs( edgeID, vertIdVec ); +// SMESH_Block::Insert( Vcom, vertIdVec[ 1 ], shapeMap); + + return nbInserted; +} + +//================================================================================ +/*! + * \brief Creates TVerticalEdgeAdaptor + * \param columnsMap - node column map + * \param parameter - normalized parameter + */ +//================================================================================ + +StdMeshers_PrismAsBlock::TVerticalEdgeAdaptor:: +TVerticalEdgeAdaptor( const TParam2ColumnMap* columnsMap, const double parameter) +{ + myNodeColumn = & getColumn( columnsMap, parameter )->second; +} + +//================================================================================ +/*! + * \brief Return coordinates for the given normalized parameter + * \param U - normalized parameter + * \retval gp_Pnt - coordinates + */ +//================================================================================ + +gp_Pnt StdMeshers_PrismAsBlock::TVerticalEdgeAdaptor::Value(const Standard_Real U) const +{ + const SMDS_MeshNode* n1; + const SMDS_MeshNode* n2; + double r = getRAndNodes( myNodeColumn, U, n1, n2 ); + return gpXYZ(n1) * ( 1 - r ) + gpXYZ(n2) * r; +} + +//================================================================================ +/*! + * \brief Return coordinates for the given normalized parameter + * \param U - normalized parameter + * \retval gp_Pnt - coordinates + */ +//================================================================================ + +gp_Pnt StdMeshers_PrismAsBlock::THorizontalEdgeAdaptor::Value(const Standard_Real U) const +{ + return mySide->TSideFace::Value( U, myV ); +} + +//================================================================================ +/*! + * \brief Return UV on pcurve for the given normalized parameter + * \param U - normalized parameter + * \retval gp_Pnt - coordinates + */ +//================================================================================ + +gp_Pnt2d StdMeshers_PrismAsBlock::TPCurveOnHorFaceAdaptor::Value(const Standard_Real U) const +{ + TParam2ColumnIt u_col1, u_col2; + double r = mySide->GetColumns( U, u_col1, u_col2 ); + gp_XY uv1 = mySide->GetNodeUV( myFace, u_col1->second[ myZ ]); + gp_XY uv2 = mySide->GetNodeUV( myFace, u_col2->second[ myZ ]); + return uv1 * ( 1 - r ) + uv2 * r; +} diff --git a/src/StdMeshers/StdMeshers_Prism_3D.hxx b/src/StdMeshers/StdMeshers_Prism_3D.hxx new file mode 100644 index 000000000..e4e12eb83 --- /dev/null +++ b/src/StdMeshers/StdMeshers_Prism_3D.hxx @@ -0,0 +1,425 @@ +// SMESH SMESH : implementaion of SMESH idl descriptions +// +// Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// +// +// File : StdMeshers_Prism_3D.hxx +// Module : SMESH + +#ifndef _SMESH_Prism_3D_HXX_ +#define _SMESH_Prism_3D_HXX_ + +#include "SMESH_3D_Algo.hxx" +#include "SMDS_TypeOfPosition.hxx" +#include "SMDS_MeshNode.hxx" +#include "SMESH_Block.hxx" +#include "SMESH_Mesh.hxx" +#include "SMESHDS_Mesh.hxx" +#include "SMESH_subMesh.hxx" +#include "SMESH_MesherHelper.hxx" + +#include +#include + +#include +#include +#include +#include +#include +#include + + +class SMESHDS_SubMesh; +class TopoDS_Edge; +class TopoDS_Faces; +struct TNode; + +//typedef std::map TNodeNodeMap; +typedef std::vector TNodeColumn; + +// map of bottom nodes to the column of nodes above them +// (the column includes the bottom nodes) +typedef std::map< TNode, TNodeColumn > TNode2ColumnMap; +typedef std::map< double, TNodeColumn > TParam2ColumnMap; +typedef std::map< double, TNodeColumn >::const_iterator TParam2ColumnIt; + +typedef TopTools_IndexedMapOfOrientedShape TBlockShapes; + +// =============================================== +/*! + * \brief Structure containing node relative data + */ +// =============================================== + +struct TNode +{ + const SMDS_MeshNode* myNode; + gp_XYZ myParams; + + gp_XYZ GetCoords() const { return gp_XYZ( myNode->X(), myNode->Y(), myNode->Z() ); } + gp_XYZ GetParams() const { return myParams; } + gp_XYZ& ChangeParams() { return myParams; } + SMDS_TypeOfPosition GetPositionType() const + { return myNode ? myNode->GetPosition()->GetTypeOfPosition() : SMDS_TOP_UNSPEC; } + + TNode(const SMDS_MeshNode* node = 0): myNode(node) {} + bool operator < (const TNode& other) const { return myNode < other.myNode; } +}; + +// =============================================================== +/*! + * \brief Tool analyzing and giving access to a prism geometry + * treating it like a block, i.e. the four side faces are + * emulated by division/uniting of missing/excess faces. + * It also manage associations between block subshapes and a mesh. + */ +// =============================================================== + +class StdMeshers_PrismAsBlock: public SMESH_Block +{ +public: + /*! + * \brief Constructor. Initialization is needed + */ + StdMeshers_PrismAsBlock(); + + ~StdMeshers_PrismAsBlock(); + + /*! + * \brief Initialization. + * \param helper - helper loaded with mesh and 3D shape + * \param shape3D - a closed shell or solid + * \retval bool - false if a mesh or a shape are KO + * + * Analyse shape geometry and mesh. + * If there are triangles on one of faces, it becomes 'bottom' + */ + bool Init(SMESH_MesherHelper* helper, const TopoDS_Shape& shape3D); + + /*! + * \brief Return number of nodes on every vertical edge + * \retval int - number of nodes including end nodes + */ + int VerticalSize() const { return myParam2ColumnMaps[0].begin()->second.size(); } + + bool HasNotQuadElemOnTop() const { return myNotQuadOnTop; } + + /*! + * \brief Return pointer to column of nodes + * \param node - bottom node from which the returned column goes up + * \retval const TNodeColumn* - the found column + */ + const TNodeColumn* GetNodeColumn(const SMDS_MeshNode* node) const; + + /*! + * \brief Return TParam2ColumnMap for a base edge + * \param baseEdgeID - base edge SMESHDS Index + * \param isReverse - columns in-block orientation + * \retval const TParam2ColumnMap& - map + */ + const TParam2ColumnMap& GetParam2ColumnMap(const int baseEdgeID, + bool & isReverse) + { + std::pair< TParam2ColumnMap*, bool > & col_frw = + myShapeIndex2ColumnMap[ baseEdgeID ]; + isReverse = !col_frw.second; + return * col_frw.first; + } + + /*! + * \brief Return pointer to mesh + * \retval SMESH_Mesh - mesh + */ + SMESH_Mesh* Mesh() const { return myHelper->GetMesh(); } + + /*! + * \brief Return pointer to mesh DS + * \retval SMESHDS_Mesh - mesh DS + */ + SMESHDS_Mesh* MeshDS() const { return Mesh()->GetMeshDS(); } + + /*! + * \brief Return submesh of a shape + * \param shapeID - shape given by in-block index + * \retval SMESH_subMesh* - found submesh + */ + SMESH_subMesh* SubMesh(const int shapeID) const + { return Mesh()->GetSubMesh( Shape( shapeID )); } + + /*! + * \brief Return submesh DS of a shape + * \param shapeID - shape given by in-block index + * \retval SMESHDS_SubMesh* - found submesh DS + */ + SMESHDS_SubMesh* SubMeshDS(const int shapeID) const + { return SubMesh(shapeID)->GetSubMeshDS(); } + + /*! + * \brief Return a in-block shape + * \param shapeID - shape given by in-block index + * \retval SMESHDS_SubMesh* - found submesh + */ + const TopoDS_Shape& Shape(const int shapeID) const + { return myShapeIDMap( shapeID ); } + + /*! + * \brief Return in-block ID of a shape + * \param shape - block subshape + * \retval int - ID or zero if the shape has no ID + */ + int ShapeID(const TopoDS_Shape& shape) const + { return myShapeIDMap.FindIndex( shape ); } + + /*! + * \brief Check curve orientation of a bootom edge + * \param meshDS - mesh DS + * \param columnsMap - node columns map of side face + * \param bottomEdge - the bootom edge + * \param sideFaceID - side face in-block ID + * \retval bool - true if orienation coinside with in-block froward orienation + */ + static bool IsForwardEdge(SMESHDS_Mesh* meshDS, + const TParam2ColumnMap& columnsMap, + const TopoDS_Edge & bottomEdge, + const int sideFaceID); + /*! + * \brief Find wall faces by bottom edges + * \param mesh - the mesh + * \param mainShape - the prism + * \param bottomFace - the bottom face + * \param bottomEdges - edges bounding the bottom face + * \param wallFaces - faces list to fill in + */ + static bool GetWallFaces( SMESH_Mesh* mesh, + const TopoDS_Shape & mainShape, + const TopoDS_Shape & bottomFace, + const std::list< TopoDS_Edge >& bottomEdges, + std::list< TopoDS_Face >& wallFaces); + +private: + + // -------------------------------------------------------------------- + /*! + * \brief Class representing a part of a geom face or + * a union of seleral faces. Or just an ordinary geom face + * + * It's parametrization is within [0,1] range. + * It redefines Adaptor3d_Surface::Value(U,V) where U and V are within [0,1] + */ + // -------------------------------------------------------------------- + class TSideFace: public Adaptor3d_Surface + { + int myID; //!< in-block ID + // map used to find out real UV by it's normalized UV + TParam2ColumnMap* myParamToColumnMap; + BRepAdaptor_Surface mySurface; + TopoDS_Edge myBaseEdge; + // first and last normalized params and orientaion for each component or it-self + vector< pair< double, double> > myParams; + bool myIsForward; + vector< TSideFace* > myComponents; + SMESH_MesherHelper * myHelper; + public: + TSideFace( SMESH_MesherHelper* helper, + const int faceID, + const TopoDS_Face& face, + const TopoDS_Edge& baseEdge, + TParam2ColumnMap* columnsMap, + const double first = 0.0, + const double last = 1.0); + TSideFace( const std::vector< TSideFace* >& components, + const std::vector< pair< double, double> > & params); + TSideFace( const TSideFace& other ); + ~TSideFace(); + bool IsComplex() const + { return ( NbComponents() > 0 || myParams[0].first != 0. || myParams[0].second != 1. ); } + int FaceID() const { return myID; } + TParam2ColumnMap* GetColumns() const { return myParamToColumnMap; } + gp_XY GetNodeUV(const TopoDS_Face& F, const SMDS_MeshNode* n) const + { return myHelper->GetNodeUV( F, n ); } + const TopoDS_Edge & BaseEdge() const { return myBaseEdge; } + int ColumnHeight() const { + if ( NbComponents() ) return GetComponent(0)->GetColumns()->begin()->second.size(); + else return GetColumns()->begin()->second.size(); } + double GetColumns(const double U, TParam2ColumnIt & col1, TParam2ColumnIt& col2 ) const; + int NbComponents() const { return myComponents.size(); } + TSideFace* GetComponent(const int i) const { return myComponents.at( i ); } + void SetComponent(const int i, TSideFace* c) + { if ( myComponents[i] ) delete myComponents[i]; myComponents[i]=c; } + TSideFace* GetComponent(const double U, double& localU) const; + bool IsForward() const { return myIsForward; } + // boundary geometry for a face + Adaptor3d_Surface* Surface() const { return new TSideFace( *this ); } + bool GetPCurves(Adaptor2d_Curve2d* pcurv[4]) const; + Adaptor2d_Curve2d* HorizPCurve(const bool isTop, const TopoDS_Face& horFace) const; + Adaptor3d_Curve* HorizCurve(const bool isTop) const; + Adaptor3d_Curve* VertiCurve(const bool isMax) const; + TopoDS_Edge GetEdge( const int edge ) const; + int InsertSubShapes( TBlockShapes& shapeMap ) const; + // redefine Adaptor methods + gp_Pnt Value(const Standard_Real U,const Standard_Real V) const; + }; + + // -------------------------------------------------------------------- + /*! + * \brief Class emulating geometry of a vertical edge + */ + // -------------------------------------------------------------------- + class TVerticalEdgeAdaptor: public Adaptor3d_Curve + { + const TNodeColumn* myNodeColumn; + public: + TVerticalEdgeAdaptor( const TParam2ColumnMap* columnsMap, const double parameter ); + gp_Pnt Value(const Standard_Real U) const; + Standard_Real FirstParameter() const { return 0; } + Standard_Real LastParameter() const { return 1; } + }; + + // -------------------------------------------------------------------- + /*! + * \brief Class emulating geometry of a hirizontal edge + */ + // -------------------------------------------------------------------- + class THorizontalEdgeAdaptor: public Adaptor3d_Curve + { + const TSideFace* mySide; + double myV; + public: + THorizontalEdgeAdaptor( const TSideFace* sideFace, const bool isTop) + :mySide(sideFace), myV( isTop ? 1.0 : 0.0 ) {} + gp_Pnt Value(const Standard_Real U) const; + Standard_Real FirstParameter() const { return 0; } + Standard_Real LastParameter() const { return 1; } + }; + + // -------------------------------------------------------------------- + /*! + * \brief Class emulating pcurve on a hirizontal face + */ + // -------------------------------------------------------------------- + class TPCurveOnHorFaceAdaptor: public Adaptor2d_Curve2d + { + const TSideFace* mySide; + int myZ; + TopoDS_Face myFace; + public: + TPCurveOnHorFaceAdaptor( const TSideFace* sideFace, + const bool isTop, + const TopoDS_Face& horFace) + : mySide(sideFace), myFace(horFace), myZ(isTop ? mySide->ColumnHeight() - 1 : 0 ) {} + gp_Pnt2d Value(const Standard_Real U) const; + Standard_Real FirstParameter() const { return 0; } + Standard_Real LastParameter() const { return 1; } + }; + // -------------------------------------------------------------------- + + bool myNotQuadOnTop; + SMESH_MesherHelper* myHelper; + TBlockShapes myShapeIDMap; + + // container of 4 side faces + TSideFace* mySide; + // node columns for each base edge + vector< TParam2ColumnMap > myParam2ColumnMaps; + // to find a column for a node by edge SMESHDS Index + map< int, pair< TParam2ColumnMap*, bool > > myShapeIndex2ColumnMap; + + + //vector< SMESH_subMesh* > mySubMeshesVec; // submesh by in-block id +}; + +// ============================================= +/*! + * \brief Algo building prisms on a prism shape + */ +// ============================================= + +class StdMeshers_Prism_3D: public SMESH_3D_Algo +{ +public: + StdMeshers_Prism_3D(int hypId, int studyId, SMESH_Gen* gen); + virtual ~StdMeshers_Prism_3D(); + + virtual bool CheckHypothesis(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + SMESH_Hypothesis::Hypothesis_Status& aStatus); + + virtual bool Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape); + + /*! + * \brief Enable removal of quadrangles from the bottom face and + * triangles creation there by projection from the top + * (sole face meshed with triangles is considered to be a bottom one). + * If there are two faces with triangles, triangles must + * be of the same topology, else the algo fails. + * The method must be called before Compute() + */ + void ProjectTriangles() { myProjectTriangles = true; } + + /*! + * \brief Create prisms + * \param nodeColumns - columns of nodes generated from nodes of a mesh face + * \param helper - helper initialized by mesh and shape to add prisms to + */ + static void AddPrisms( vector & nodeColumns, + SMESH_MesherHelper* helper); + +private: + + /*! + * \brief Find correspondence between bottom and top nodes. + * If elements on the bottom and top faces are topologically different, + * and projection is possible and allowed, perform the projection + * \retval bool - is a success or not + */ + bool assocOrProjBottom2Top(); + + /*! + * \brief Remove quadrangles from the top face and + * create triangles there by projection from the bottom + * \retval bool - a success or not + */ + bool projectBottomToTop(); + + /*! + * \brief Set projection coordinates of a node to a face and it's subshapes + * \param faceID - the face given by in-block ID + * \param params - node normalized parameters + * \retval bool - is a success + */ + bool setFaceAndEdgesXYZ( const int faceID, const gp_XYZ& params, int z ); + +private: + + bool myProjectTriangles; + + StdMeshers_PrismAsBlock myBlock; + SMESH_MesherHelper* myHelper; + + vector myShapeXYZ; // point on each sub-shape + + // map of bottom nodes to the column of nodes above them + // (the column includes the bottom node) + typedef std::map< TNode, TNodeColumn > TNode2ColumnMap; + TNode2ColumnMap myBotToColumnMap; +}; + +#endif diff --git a/src/StdMeshers/StdMeshers_ProjectionSource1D.cxx b/src/StdMeshers/StdMeshers_ProjectionSource1D.cxx new file mode 100644 index 000000000..18a25a315 --- /dev/null +++ b/src/StdMeshers/StdMeshers_ProjectionSource1D.cxx @@ -0,0 +1,219 @@ +// SMESH SMESH : idl implementation based on 'SMESH' unit's classes +// +// Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// +// +// File : StdMeshers_ProjectionSource1D.cxx +// Author : Edward AGAPOV +// Module : SMESH +// $Header$ + +#include "StdMeshers_ProjectionSource1D.hxx" + +#include "SMESH_Mesh.hxx" + +#include "utilities.h" + +#include + +using namespace std; + + +//============================================================================= +/*! + * StdMeshers_ProjectionSource1D::StdMeshers_ProjectionSource1D + * + * Constructor + */ +//============================================================================= + +StdMeshers_ProjectionSource1D::StdMeshers_ProjectionSource1D(int hypId, int studyId, + SMESH_Gen * gen) + : SMESH_Hypothesis(hypId, studyId, gen) +{ + _name = "ProjectionSource1D"; // used by Projection_1D + _param_algo_dim = 1; // 1D + _sourceMesh = 0; +} + +//============================================================================= +/*! + * StdMeshers_ProjectionSource1D::~StdMeshers_ProjectionSource1D + * + * Destructor + */ +//============================================================================= + +StdMeshers_ProjectionSource1D::~StdMeshers_ProjectionSource1D() +{ + MESSAGE( "StdMeshers_ProjectionSource1D::~StdMeshers_ProjectionSource1D" ); +} + +//============================================================================= + /*! + * Sets source to take a mesh pattern from + */ +//============================================================================= + +void StdMeshers_ProjectionSource1D::SetSourceEdge(const TopoDS_Shape& edge) + throw ( SALOME_Exception ) +{ + if ( edge.IsNull() ) + throw SALOME_Exception(LOCALIZED("Null edge is not allowed")); + + if ( edge.ShapeType() != TopAbs_EDGE ) + throw SALOME_Exception(LOCALIZED("Wrong shape type")); + + if ( !_sourceEdge.IsSame( edge ) ) + { + _sourceEdge = TopoDS::Edge( edge ); + + NotifySubMeshesHypothesisModification(); + } +} + +//============================================================================= +/*! + * Sets vertex association between the source edge and the target one. + * This parameter is optional + */ +//============================================================================= + +void StdMeshers_ProjectionSource1D::SetVertexAssociation(const TopoDS_Shape& sourceVertex, + const TopoDS_Shape& targetVertex) + throw ( SALOME_Exception ) +{ + if ( sourceVertex.IsNull() != targetVertex.IsNull() ) + throw SALOME_Exception(LOCALIZED("Two or none vertices must be provided")); + + if ( !sourceVertex.IsNull() ) { + if ( sourceVertex.ShapeType() != TopAbs_VERTEX || + targetVertex.ShapeType() != TopAbs_VERTEX ) + throw SALOME_Exception(LOCALIZED("Wrong shape type")); + } + + if ( !_sourceVertex.IsSame( sourceVertex ) || + !_targetVertex.IsSame( targetVertex ) ) + { + _sourceVertex = TopoDS::Vertex( sourceVertex ); + _targetVertex = TopoDS::Vertex( targetVertex ); + + NotifySubMeshesHypothesisModification(); + } +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +ostream & StdMeshers_ProjectionSource1D::SaveTo(ostream & save) +{ + // we store it in order to be able to detect that hypo is really modified + save << " " << _sourceEdge.TShape().operator->() ; + save << " " << _sourceVertex.TShape().operator->(); + save << " " << _targetVertex.TShape().operator->(); + save << " " << ( _sourceMesh ? _sourceMesh->GetId() : -1 ); + return save; +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +istream & StdMeshers_ProjectionSource1D::LoadFrom(istream & load) +{ + // impossible to restore w/o any context + return load; +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +ostream & operator <<(ostream & save, StdMeshers_ProjectionSource1D & hyp) +{ + return hyp.SaveTo( save ); +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +istream & operator >>(istream & load, StdMeshers_ProjectionSource1D & hyp) +{ + return hyp.LoadFrom( load ); +} + +//================================================================================ +/*! + * \brief Initialize start and end length by the mesh built on the geometry + * \param theMesh - the built mesh + * \param theShape - the geometry of interest + * \retval bool - true if parameter values have been successfully defined + */ +//================================================================================ + +bool StdMeshers_ProjectionSource1D::SetParametersByMesh(const SMESH_Mesh* , + const TopoDS_Shape& ) +{ + return false; +} + +//================================================================================ +/*! + * \brief Return all parameters + */ +//================================================================================ + +void StdMeshers_ProjectionSource1D::GetStoreParams(TopoDS_Shape& s1, + TopoDS_Shape& s2, + TopoDS_Shape& s3) const +{ + s1 = _sourceEdge; + s2 = _sourceVertex; + s3 = _targetVertex; +} + +//================================================================================ +/*! + * \brief Set all parameters without notifying on modification + */ +//================================================================================ + +void StdMeshers_ProjectionSource1D::RestoreParams(const TopoDS_Shape& s1, + const TopoDS_Shape& s2, + const TopoDS_Shape& s3, + SMESH_Mesh* mesh) +{ + _sourceEdge = TopoDS::Edge( s1 ); + _sourceVertex = TopoDS::Vertex( s2 ); + _targetVertex = TopoDS::Vertex( s3 ); + _sourceMesh = mesh; +} + diff --git a/src/StdMeshers/StdMeshers_ProjectionSource1D.hxx b/src/StdMeshers/StdMeshers_ProjectionSource1D.hxx new file mode 100644 index 000000000..e1d019a1c --- /dev/null +++ b/src/StdMeshers/StdMeshers_ProjectionSource1D.hxx @@ -0,0 +1,142 @@ +// SMESH SMESH : idl implementation based on 'SMESH' unit's calsses +// +// Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// +// +// File : StdMeshers_ProjectionSource1D.hxx +// Author : Edward AGAPOV +// Module : SMESH +// $Header$ + +#ifndef _SMESH_ProjectionSource1D_HXX_ +#define _SMESH_ProjectionSource1D_HXX_ + +#include "SMESH_Hypothesis.hxx" +#include "Utils_SALOME_Exception.hxx" + +#include +#include + +class SMESH_Gen; + +// ========================================================= + /*! + * This hypothesis specifies a meshed edge to take a mesh pattern from + * and optionally association of vertices between the source edge and a + * target one (where a hipothesis is assigned to) + */ +// ========================================================= + +class StdMeshers_ProjectionSource1D: public SMESH_Hypothesis +{ +public: + // Constructor + StdMeshers_ProjectionSource1D( int hypId, int studyId, SMESH_Gen * gen ); + // Destructor + virtual ~StdMeshers_ProjectionSource1D(); + + /*! + * Sets source to take a mesh pattern from + */ + void SetSourceEdge(const TopoDS_Shape& edge) + throw ( SALOME_Exception ); + + /*! + * Returns the source edge + */ + TopoDS_Edge GetSourceEdge() const { return _sourceEdge; } + + /*! + * Sets source to take a mesh pattern from + */ + void SetSourceMesh(SMESH_Mesh* mesh) { _sourceMesh = mesh; } + + /*! + * Return source mesh + */ + SMESH_Mesh* GetSourceMesh() const { return _sourceMesh; } + + /*! + * Sets vertex association between the source edge and the target one. + * This parameter is optional + */ + void SetVertexAssociation(const TopoDS_Shape& sourceVertex, + const TopoDS_Shape& targetVertex) + throw ( SALOME_Exception ); + + /*! + * Returns the vertex associated with the target vertex. + * Result may be nil if association not set + */ + TopoDS_Vertex GetSourceVertex() const { return _sourceVertex; } + + /*! + * Returns the vertex associated with the source vertex. + * Result may be nil if association not set + */ + TopoDS_Vertex GetTargetVertex() const { return _targetVertex; } + + /*! + * \brief Test if vertex association defined + * \retval bool - test result + */ + bool HasVertexAssociation() const + { return ( !_sourceVertex.IsNull() && !_targetVertex.IsNull() ); } + + /*! + * \brief Return all parameters + */ + void GetStoreParams(TopoDS_Shape& s1, + TopoDS_Shape& s2, + TopoDS_Shape& s3) const; + + /*! + * \brief Set all parameters without notifying on modification + */ + void RestoreParams(const TopoDS_Shape& s1, + const TopoDS_Shape& s2, + const TopoDS_Shape& s3, + SMESH_Mesh* mesh); + + virtual std::ostream & SaveTo(std::ostream & save); + virtual std::istream & LoadFrom(std::istream & load); + friend std::ostream & operator <<(std::ostream & save, StdMeshers_ProjectionSource1D & hyp); + friend std::istream & operator >>(std::istream & load, StdMeshers_ProjectionSource1D & hyp); + + /*! + * \brief Initialize parameters by the mesh built on the geometry + * \param theMesh - the built mesh + * \param theShape - the geometry of interest + * \retval bool - true if parameter values have been successfully defined + * + * Implementation does noting + */ + virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); + +protected: + + TopoDS_Edge _sourceEdge; + SMESH_Mesh* _sourceMesh; + TopoDS_Vertex _sourceVertex; + TopoDS_Vertex _targetVertex; +}; + +#endif diff --git a/src/StdMeshers/StdMeshers_ProjectionSource2D.cxx b/src/StdMeshers/StdMeshers_ProjectionSource2D.cxx new file mode 100644 index 000000000..909b90354 --- /dev/null +++ b/src/StdMeshers/StdMeshers_ProjectionSource2D.cxx @@ -0,0 +1,287 @@ +// SMESH SMESH : idl implementation based on 'SMESH' unit's classes +// +// Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// +// +// File : StdMeshers_ProjectionSource2D.cxx +// Author : Edward AGAPOV +// Module : SMESH +// $Header$ + + +#include "StdMeshers_ProjectionSource2D.hxx" + +#include "SMESH_Mesh.hxx" + +#include "utilities.h" + +#include + +using namespace std; + +//============================================================================= +/*! + * StdMeshers_ProjectionSource2D::StdMeshers_ProjectionSource2D + * + * Constructor + */ +//============================================================================= + +StdMeshers_ProjectionSource2D::StdMeshers_ProjectionSource2D(int hypId, int studyId, + SMESH_Gen * gen) + : SMESH_Hypothesis(hypId, studyId, gen) +{ + _name = "ProjectionSource2D"; // used by Projection_2D + _param_algo_dim = 2; // 2D + _sourceMesh = 0; +} + +//============================================================================= +/*! + * StdMeshers_ProjectionSource2D::~StdMeshers_ProjectionSource2D + * + * Destructor + */ +//============================================================================= + +StdMeshers_ProjectionSource2D::~StdMeshers_ProjectionSource2D() +{ + MESSAGE( "StdMeshers_ProjectionSource2D::~StdMeshers_ProjectionSource2D" ); +} + +//============================================================================= + /*! + * Sets a source to take a mesh pattern from + */ +//============================================================================= + +void StdMeshers_ProjectionSource2D::SetSourceFace(const TopoDS_Shape& Face) + throw ( SALOME_Exception ) +{ + if ( Face.IsNull() ) + throw SALOME_Exception(LOCALIZED("Null Face is not allowed")); + + if ( Face.ShapeType() != TopAbs_FACE ) + throw SALOME_Exception(LOCALIZED("Wrong shape type")); + + if ( !_sourceFace.IsSame( Face ) ) + { + _sourceFace = TopoDS::Face( Face ); + + NotifySubMeshesHypothesisModification(); + } +} + +//============================================================================= +/*! + * Sets vertex association between the source face and the target one. + * This parameter is optional. + * Two vertices must belong to one edge of a face + */ +//============================================================================= + +void StdMeshers_ProjectionSource2D::SetVertexAssociation(const TopoDS_Shape& sourceVertex1, + const TopoDS_Shape& sourceVertex2, + const TopoDS_Shape& targetVertex1, + const TopoDS_Shape& targetVertex2) + throw ( SALOME_Exception ) +{ + if ( sourceVertex1.IsNull() != targetVertex1.IsNull() || + sourceVertex2.IsNull() != targetVertex2.IsNull() || + sourceVertex1.IsNull() != targetVertex2.IsNull() ) + throw SALOME_Exception(LOCALIZED("Two or none pairs of vertices must be provided")); + + if ( !sourceVertex1.IsNull() ) { + if ( sourceVertex1.ShapeType() != TopAbs_VERTEX || + sourceVertex2.ShapeType() != TopAbs_VERTEX || + targetVertex1.ShapeType() != TopAbs_VERTEX || + targetVertex2.ShapeType() != TopAbs_VERTEX ) + throw SALOME_Exception(LOCALIZED("Wrong shape type")); + } + + if ( !_sourceVertex1.IsSame( sourceVertex1 ) || + !_sourceVertex2.IsSame( sourceVertex2 ) || + !_targetVertex1.IsSame( targetVertex1 ) || + !_targetVertex2.IsSame( targetVertex2 ) ) + { + _sourceVertex1 = TopoDS::Vertex( sourceVertex1 ); + _sourceVertex2 = TopoDS::Vertex( sourceVertex2 ); + _targetVertex1 = TopoDS::Vertex( targetVertex1 ); + _targetVertex2 = TopoDS::Vertex( targetVertex2 ); + + NotifySubMeshesHypothesisModification(); + } +} + +//============================================================================= +/*! + * Returns the source face + */ +//============================================================================= + +TopoDS_Face StdMeshers_ProjectionSource2D::GetSourceFace() const +{ + return _sourceFace; +} + +//============================================================================= +/*! + * Returns the vertex associated with the target vertex. + * Result may be nil if association not set + */ +//============================================================================= + +TopoDS_Vertex StdMeshers_ProjectionSource2D::GetSourceVertex(int i) const + throw ( SALOME_Exception ) +{ + if ( i == 1 ) + return _sourceVertex1; + else if ( i == 2 ) + return _sourceVertex2; + else + throw SALOME_Exception(LOCALIZED("Wrong vertex index")); +} + +//============================================================================= +/*! + * Returns the -th target vertex associated with the -th source vertex. + * Result may be nil if association not set. + */ +//============================================================================= + +TopoDS_Vertex StdMeshers_ProjectionSource2D::GetTargetVertex(int i) const + throw ( SALOME_Exception ) +{ + if ( i == 1 ) + return _targetVertex1; + else if ( i == 2 ) + return _targetVertex2; + else + throw SALOME_Exception(LOCALIZED("Wrong vertex index")); +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +ostream & StdMeshers_ProjectionSource2D::SaveTo(ostream & save) +{ + // we store it in order to be able to detect that hypo is really modified + save << " " << _sourceFace.TShape().operator->() ; + save << " " << _sourceVertex1.TShape().operator->(); + save << " " << _targetVertex1.TShape().operator->(); + save << " " << _sourceVertex2.TShape().operator->(); + save << " " << _targetVertex2.TShape().operator->(); + save << " " << ( _sourceMesh ? _sourceMesh->GetId() : -1 ); + return save; +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +istream & StdMeshers_ProjectionSource2D::LoadFrom(istream & load) +{ + // impossible to restore w/o any context + // It is done by servant + return load; +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +ostream & operator <<(ostream & save, StdMeshers_ProjectionSource2D & hyp) +{ + return hyp.SaveTo( save ); +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +istream & operator >>(istream & load, StdMeshers_ProjectionSource2D & hyp) +{ + return hyp.LoadFrom( load ); +} + +//================================================================================ +/*! + * \brief Initialize start and end length by the mesh built on the geometry + * \param theMesh - the built mesh + * \param theShape - the geometry of interest + * \retval bool - true if parameter values have been successfully defined + */ +//================================================================================ + +bool StdMeshers_ProjectionSource2D::SetParametersByMesh(const SMESH_Mesh* , + const TopoDS_Shape& ) +{ + return false; +} + +//================================================================================ +/*! + * \brief Return all parameters + */ +//================================================================================ + +void StdMeshers_ProjectionSource2D::GetStoreParams(TopoDS_Shape& s1, + TopoDS_Shape& s2, + TopoDS_Shape& s3, + TopoDS_Shape& s4, + TopoDS_Shape& s5) const +{ + s1 = _sourceFace; + s2 = _sourceVertex1; + s3 = _sourceVertex2; + s4 = _targetVertex1; + s5 = _targetVertex2; +} + +//================================================================================ +/*! + * \brief Set all parameters without notifying on modification + */ +//================================================================================ + +void StdMeshers_ProjectionSource2D::RestoreParams(const TopoDS_Shape& s1, + const TopoDS_Shape& s2, + const TopoDS_Shape& s3, + const TopoDS_Shape& s4, + const TopoDS_Shape& s5, + SMESH_Mesh* mesh) +{ + _sourceFace = TopoDS::Face( s1 ); + _sourceVertex1 = TopoDS::Vertex( s2 ); + _sourceVertex2 = TopoDS::Vertex( s3 ); + _targetVertex1 = TopoDS::Vertex( s4 ); + _targetVertex2 = TopoDS::Vertex( s5 ); + _sourceMesh = mesh; +} diff --git a/src/StdMeshers/StdMeshers_ProjectionSource2D.hxx b/src/StdMeshers/StdMeshers_ProjectionSource2D.hxx new file mode 100644 index 000000000..ec4a33ee6 --- /dev/null +++ b/src/StdMeshers/StdMeshers_ProjectionSource2D.hxx @@ -0,0 +1,155 @@ +// SMESH SMESH : idl implementation based on 'SMESH' unit's calsses +// +// Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// +// +// File : StdMeshers_ProjectionSource2D.hxx +// Author : Edward AGAPOV +// Module : SMESH +// $Header$ + +#ifndef _SMESH_ProjectionSource2D_HXX_ +#define _SMESH_ProjectionSource2D_HXX_ + +#include "SMESH_Hypothesis.hxx" +#include "Utils_SALOME_Exception.hxx" + +#include +#include + +class SMESH_Gen; + +// ========================================================= +/*! + * This hypothesis specifies a meshed face to take a mesh pattern from + * and optionally association of vertices between the source face and a + * target one (where a hipothesis is assigned to) + */ +// ========================================================= + +class StdMeshers_ProjectionSource2D: public SMESH_Hypothesis +{ +public: + // Constructor + StdMeshers_ProjectionSource2D( int hypId, int studyId, SMESH_Gen * gen ); + // Destructor + virtual ~StdMeshers_ProjectionSource2D(); + + /*! + * Sets a source to take a mesh pattern from + */ + void SetSourceFace(const TopoDS_Shape& face) + throw ( SALOME_Exception ); + + /*! + * Returns the source face + */ + TopoDS_Face GetSourceFace() const; + + /*! + * Sets source to take a mesh pattern from + */ + void SetSourceMesh(SMESH_Mesh* mesh) { _sourceMesh = mesh; } + + /*! + * Return source mesh + */ + SMESH_Mesh* GetSourceMesh() const { return _sourceMesh; } + + /*! + * Sets vertex association between the source face and the target one. + * This parameter is optional. + * Two vertices must belong to one edge of a face + */ + void SetVertexAssociation(const TopoDS_Shape& sourceVertex1, + const TopoDS_Shape& sourceVertex2, + const TopoDS_Shape& targetVertex1, + const TopoDS_Shape& targetVertex2) + throw ( SALOME_Exception ); + + /*! + * Returns the -th source vertex associated with the -th target vertex. + * Result may be nil if association not set. + * Valid indices are 1 and 2 + */ + TopoDS_Vertex GetSourceVertex(int i) const throw ( SALOME_Exception ); + + /*! + * Returns the -th target vertex associated with the -th source vertex. + * Result may be nil if association not set. + * Valid indices are 1 and 2 + */ + TopoDS_Vertex GetTargetVertex(int i) const throw ( SALOME_Exception ); + + /*! + * \brief Test if vertex association defined + * \retval bool - test result + */ + bool HasVertexAssociation() const + { return ( !_sourceVertex1.IsNull() && !_targetVertex1.IsNull() && + !_sourceVertex2.IsNull() && !_targetVertex2.IsNull()); } + + /*! + * \brief Return all parameters + */ + void GetStoreParams(TopoDS_Shape& s1, + TopoDS_Shape& s2, + TopoDS_Shape& s3, + TopoDS_Shape& s4, + TopoDS_Shape& s5) const; + + /*! + * \brief Set all parameters without notifying on modification + */ + void RestoreParams(const TopoDS_Shape& s1, + const TopoDS_Shape& s2, + const TopoDS_Shape& s3, + const TopoDS_Shape& s4, + const TopoDS_Shape& s5, + SMESH_Mesh* mesh); + + virtual std::ostream & SaveTo(std::ostream & save); + virtual std::istream & LoadFrom(std::istream & load); + friend std::ostream & operator <<(std::ostream & save, StdMeshers_ProjectionSource2D & hyp); + friend std::istream & operator >>(std::istream & load, StdMeshers_ProjectionSource2D & hyp); + + /*! + * \brief Initialize parameters by the mesh built on the geometry + * \param theMesh - the built mesh + * \param theShape - the geometry of interest + * \retval bool - true if parameter values have been successfully defined + * + * Implementation does noting + */ + virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); + +protected: + + TopoDS_Face _sourceFace; + SMESH_Mesh* _sourceMesh; + TopoDS_Vertex _sourceVertex1; + TopoDS_Vertex _sourceVertex2; + TopoDS_Vertex _targetVertex1; + TopoDS_Vertex _targetVertex2; +}; + +#endif + diff --git a/src/StdMeshers/StdMeshers_ProjectionSource3D.cxx b/src/StdMeshers/StdMeshers_ProjectionSource3D.cxx new file mode 100644 index 000000000..3e4c33e8c --- /dev/null +++ b/src/StdMeshers/StdMeshers_ProjectionSource3D.cxx @@ -0,0 +1,286 @@ +// SMESH SMESH : idl implementation based on 'SMESH' unit's classes +// +// Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// +// +// File : StdMeshers_ProjectionSource3D.cxx +// Author : Edward AGAPOV +// Module : SMESH +// $Header$ + +#include "StdMeshers_ProjectionSource3D.hxx" + +#include "utilities.h" +#include "SMESH_Gen.hxx" + +#include + +using namespace std; + +//============================================================================= +/*! + * StdMeshers_ProjectionSource3D::StdMeshers_ProjectionSource3D + * + * Constructor + */ +//============================================================================= + +StdMeshers_ProjectionSource3D::StdMeshers_ProjectionSource3D(int hypId, int studyId, + SMESH_Gen * gen) + : SMESH_Hypothesis(hypId, studyId, gen) +{ + _name = "ProjectionSource3D"; // used by Projection_3D + _param_algo_dim = 3; // 3D + _sourceMesh = 0; +} + +//============================================================================= +/*! + * StdMeshers_ProjectionSource3D::~StdMeshers_ProjectionSource3D + * + * Destructor + */ +//============================================================================= + +StdMeshers_ProjectionSource3D::~StdMeshers_ProjectionSource3D() +{ + MESSAGE( "StdMeshers_ProjectionSource3D::~StdMeshers_ProjectionSource3D" ); +} + +//============================================================================= + /*! + * Sets a source to take a mesh pattern from + */ +//============================================================================= + +void StdMeshers_ProjectionSource3D::SetSource3DShape(const TopoDS_Shape& Shape) + throw ( SALOME_Exception ) +{ + if ( Shape.IsNull() ) + throw SALOME_Exception(LOCALIZED("Null Shape is not allowed")); + + if ( SMESH_Gen::GetShapeDim( Shape ) != 3 ) + throw SALOME_Exception(LOCALIZED("Wrong shape type")); + + if ( !_sourceShape.IsSame( Shape ) ) + { + _sourceShape = Shape; + + NotifySubMeshesHypothesisModification(); + } +} + +//============================================================================= +/*! + * Sets vertex association between the source shape and the target one. + * This parameter is optional. + * Two vertices must belong to one edge of a shape + */ +//============================================================================= + +void StdMeshers_ProjectionSource3D::SetVertexAssociation(const TopoDS_Shape& sourceVertex1, + const TopoDS_Shape& sourceVertex2, + const TopoDS_Shape& targetVertex1, + const TopoDS_Shape& targetVertex2) + throw ( SALOME_Exception ) +{ + if ( sourceVertex1.IsNull() != targetVertex1.IsNull() || + sourceVertex2.IsNull() != targetVertex2.IsNull() || + sourceVertex1.IsNull() != targetVertex2.IsNull() ) + throw SALOME_Exception(LOCALIZED("Two or none pairs of vertices must be provided")); + + if ( !sourceVertex1.IsNull() ) { + if ( sourceVertex1.ShapeType() != TopAbs_VERTEX || + sourceVertex2.ShapeType() != TopAbs_VERTEX || + targetVertex1.ShapeType() != TopAbs_VERTEX || + targetVertex2.ShapeType() != TopAbs_VERTEX ) + throw SALOME_Exception(LOCALIZED("Wrong shape type")); + } + + if ( !_sourceVertex1.IsSame( sourceVertex1 ) || + !_sourceVertex2.IsSame( sourceVertex2 ) || + !_targetVertex1.IsSame( targetVertex1 ) || + !_targetVertex2.IsSame( targetVertex2 ) ) + { + _sourceVertex1 = TopoDS::Vertex( sourceVertex1 ); + _sourceVertex2 = TopoDS::Vertex( sourceVertex2 ); + _targetVertex1 = TopoDS::Vertex( targetVertex1 ); + _targetVertex2 = TopoDS::Vertex( targetVertex2 ); + + NotifySubMeshesHypothesisModification(); + } +} + +//============================================================================= +/*! + * Returns the source face + */ +//============================================================================= + +TopoDS_Shape StdMeshers_ProjectionSource3D::GetSource3DShape() const +{ + return _sourceShape; +} + +//============================================================================= +/*! + * Returns the vertex associated with the target vertex. + * Result may be nil if association not set + */ +//============================================================================= + +TopoDS_Vertex StdMeshers_ProjectionSource3D::GetSourceVertex(int i) const + throw ( SALOME_Exception ) +{ + if ( i == 1 ) + return _sourceVertex1; + else if ( i == 2 ) + return _sourceVertex2; + else + throw SALOME_Exception(LOCALIZED("Wrong vertex index")); +} + +//============================================================================= +/*! + * Returns the -th target vertex associated with the -th source vertex. + * Result may be nil if association not set. + */ +//============================================================================= + +TopoDS_Vertex StdMeshers_ProjectionSource3D::GetTargetVertex(int i) const + throw ( SALOME_Exception ) +{ + if ( i == 1 ) + return _targetVertex1; + else if ( i == 2 ) + return _targetVertex2; + else + throw SALOME_Exception(LOCALIZED("Wrong vertex index")); +} + + +//============================================================================= +/*! + * + */ +//============================================================================= + +ostream & StdMeshers_ProjectionSource3D::SaveTo(ostream & save) +{ + // we store it in order to be able to detect that hypo is really modified + save << " " << _sourceShape.TShape().operator->() ; + save << " " << _sourceVertex1.TShape().operator->(); + save << " " << _targetVertex1.TShape().operator->(); + save << " " << _sourceVertex2.TShape().operator->(); + save << " " << _targetVertex2.TShape().operator->(); + save << " " << ( _sourceMesh ? _sourceMesh->GetId() : -1 ); + return save; +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +istream & StdMeshers_ProjectionSource3D::LoadFrom(istream & load) +{ + // impossible to restore w/o any context + // It is done by servant + return load; +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +ostream & operator <<(ostream & save, StdMeshers_ProjectionSource3D & hyp) +{ + return hyp.SaveTo( save ); +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +istream & operator >>(istream & load, StdMeshers_ProjectionSource3D & hyp) +{ + return hyp.LoadFrom( load ); +} + +//================================================================================ +/*! + * \brief Initialize start and end length by the mesh built on the geometry + * \param theMesh - the built mesh + * \param theShape - the geometry of interest + * \retval bool - true if parameter values have been successfully defined + */ +//================================================================================ + +bool StdMeshers_ProjectionSource3D::SetParametersByMesh(const SMESH_Mesh* , + const TopoDS_Shape& ) +{ + return false; +} + +//================================================================================ +/*! + * \brief Return all parameters + */ +//================================================================================ + +void StdMeshers_ProjectionSource3D::GetStoreParams(TopoDS_Shape& s1, + TopoDS_Shape& s2, + TopoDS_Shape& s3, + TopoDS_Shape& s4, + TopoDS_Shape& s5) const +{ + s1 = _sourceShape; + s2 = _sourceVertex1; + s3 = _sourceVertex2; + s4 = _targetVertex1; + s5 = _targetVertex2; +} + +//================================================================================ +/*! + * \brief Set all parameters without notifying on modification + */ +//================================================================================ + +void StdMeshers_ProjectionSource3D::RestoreParams(const TopoDS_Shape& s1, + const TopoDS_Shape& s2, + const TopoDS_Shape& s3, + const TopoDS_Shape& s4, + const TopoDS_Shape& s5, + SMESH_Mesh* mesh) +{ + _sourceShape = s1; + _sourceVertex1 = TopoDS::Vertex( s2 ); + _sourceVertex2 = TopoDS::Vertex( s3 ); + _targetVertex1 = TopoDS::Vertex( s4 ); + _targetVertex2 = TopoDS::Vertex( s5 ); + _sourceMesh = mesh; +} diff --git a/src/StdMeshers/StdMeshers_ProjectionSource3D.hxx b/src/StdMeshers/StdMeshers_ProjectionSource3D.hxx new file mode 100644 index 000000000..493851ab1 --- /dev/null +++ b/src/StdMeshers/StdMeshers_ProjectionSource3D.hxx @@ -0,0 +1,153 @@ +// SMESH SMESH : idl implementation based on 'SMESH' unit's calsses +// +// Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// +// +// File : StdMeshers_ProjectionSource3D.hxx +// Author : Edward AGAPOV +// Module : SMESH +// $Header$ + +#ifndef _SMESH_ProjectionSource3D_HXX_ +#define _SMESH_ProjectionSource3D_HXX_ + +#include "SMESH_Hypothesis.hxx" +#include "Utils_SALOME_Exception.hxx" + +#include + +class SMESH_Gen; + +// ========================================================= +/*! + * This hypothesis specifies a meshed shell or solid to take a mesh pattern from + * and optionally association of vertices between the source shape and a + * target one (where a hipothesis is assigned to) + */ +// ========================================================= + +class StdMeshers_ProjectionSource3D: public SMESH_Hypothesis +{ +public: + // Constructor + StdMeshers_ProjectionSource3D( int hypId, int studyId, SMESH_Gen * gen ); + // Destructor + virtual ~StdMeshers_ProjectionSource3D(); + + /*! + * Sets a source to take a mesh pattern from + */ + void SetSource3DShape(const TopoDS_Shape& shape) + throw ( SALOME_Exception ); + + /*! + * Returns the source shape + */ + TopoDS_Shape GetSource3DShape() const; + + /*! + * Sets source to take a mesh pattern from + */ + void SetSourceMesh(SMESH_Mesh* mesh) { _sourceMesh = mesh; } + + /*! + * Return source mesh + */ + SMESH_Mesh* GetSourceMesh() const { return _sourceMesh; } + + /*! + * Sets vertex association between the source shape and the target one. + * This parameter is optional. + * Two vertices must belong to one edge of a shape + */ + void SetVertexAssociation(const TopoDS_Shape& sourceVertex1, + const TopoDS_Shape& sourceVertex2, + const TopoDS_Shape& targetVertex1, + const TopoDS_Shape& targetVertex2) + throw ( SALOME_Exception ); + + /*! + * Returns the -th source vertex associated with the -th target vertex. + * Result may be nil if association not set. + */ + TopoDS_Vertex GetSourceVertex(int i) const throw ( SALOME_Exception ); + + /*! + * Returns the -th target vertex associated with the -th source vertex. + * Result may be nil if association not set. + */ + TopoDS_Vertex GetTargetVertex(int i) const throw ( SALOME_Exception ); + + /*! + * \brief Test if vertex association defined + * \retval bool - test result + */ + bool HasVertexAssociation() const + { return ( !_sourceVertex1.IsNull() && !_targetVertex1.IsNull() && + !_sourceVertex2.IsNull() && !_targetVertex2.IsNull()); } + + /*! + * \brief Return all parameters + */ + void GetStoreParams(TopoDS_Shape& s1, + TopoDS_Shape& s2, + TopoDS_Shape& s3, + TopoDS_Shape& s4, + TopoDS_Shape& s5) const; + + /*! + * \brief Set all parameters without notifying on modification + */ + void RestoreParams(const TopoDS_Shape& s1, + const TopoDS_Shape& s2, + const TopoDS_Shape& s3, + const TopoDS_Shape& s4, + const TopoDS_Shape& s5, + SMESH_Mesh* mesh); + + virtual std::ostream & SaveTo(std::ostream & save); + virtual std::istream & LoadFrom(std::istream & load); + friend std::ostream & operator <<(std::ostream & save, StdMeshers_ProjectionSource3D & hyp); + friend std::istream & operator >>(std::istream & load, StdMeshers_ProjectionSource3D & hyp); + + /*! + * \brief Initialize parameters by the mesh built on the geometry + * \param theMesh - the built mesh + * \param theShape - the geometry of interest + * \retval bool - true if parameter values have been successfully defined + * + * Implementation does noting + */ + virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); + +protected: + + TopoDS_Shape _sourceShape; + SMESH_Mesh* _sourceMesh; + TopoDS_Vertex _sourceVertex1; + TopoDS_Vertex _sourceVertex2; + TopoDS_Vertex _targetVertex1; + TopoDS_Vertex _targetVertex2; + +}; + +#endif + diff --git a/src/StdMeshers/StdMeshers_ProjectionUtils.cxx b/src/StdMeshers/StdMeshers_ProjectionUtils.cxx new file mode 100644 index 000000000..2afedd4ce --- /dev/null +++ b/src/StdMeshers/StdMeshers_ProjectionUtils.cxx @@ -0,0 +1,1241 @@ +// SMESH SMESH : idl implementation based on 'SMESH' unit's calsses +// +// Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// +// +// File : StdMeshers_ProjectionUtils.cxx +// Created : Fri Oct 27 10:24:28 2006 +// Author : Edward AGAPOV (eap) + + +#include "StdMeshers_ProjectionUtils.hxx" + +#include "StdMeshers_ProjectionSource1D.hxx" +#include "StdMeshers_ProjectionSource2D.hxx" +#include "StdMeshers_ProjectionSource3D.hxx" + +#include "SMESH_Algo.hxx" +#include "SMESH_Block.hxx" +#include "SMESH_Gen.hxx" +#include "SMESH_Hypothesis.hxx" +#include "SMESH_IndexedDataMapOfShapeIndexedMapOfShape.hxx" +#include "SMESH_Mesh.hxx" +#include "SMESH_MeshEditor.hxx" +#include "SMESH_subMesh.hxx" +#include "SMDS_EdgePosition.hxx" + +#include "utilities.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define RETURN_BAD_RESULT(msg) { MESSAGE(msg); return false; } +#define SHOW_VERTEX(v,msg) // { \ +// if ( v.IsNull() ) cout << msg << " NULL SHAPE" << endl; \ +// else if (v.ShapeType() == TopAbs_VERTEX) {\ +// gp_Pnt p = BRep_Tool::Pnt( TopoDS::Vertex( v ));\ +// cout << msg << (v).TShape().operator->()<<" ( " <()<::const_iterator e = l.begin();\ +// for ( int i = 0; e != l.end(); ++e, ++i ) {\ +// cout << i << "V (" << TopExp::FirstVertex( *e, true ).TShape().operator->() << ") "\ +// << i << "E (" << e->TShape().operator->() << "); "; }\ +// cout << endl;\ +// } + +namespace { + //================================================================================ + /*! + * \brief Reverse order of edges in a list and their orientation + * \param edges - list of edges to reverse + * \param nbEdges - number of edges to reverse + */ + //================================================================================ + + void Reverse( list< TopoDS_Edge > & edges, const int nbEdges ) + { + SHOW_LIST("BEFORE REVERSE", edges); + + list< TopoDS_Edge >::iterator eIt = edges.begin(); + if ( edges.size() == nbEdges ) + { + edges.reverse(); + } + else // reverse only the given nb of edges + { + // look for the last edge to be reversed + list< TopoDS_Edge >::iterator eBackIt = edges.begin(); + for ( int i = 1; i < nbEdges; ++i ) + ++eBackIt; + // reverse + while ( eIt != eBackIt ) { + std::swap( *eIt, *eBackIt ); + SHOW_LIST("# AFTER SWAP", edges) + if ( (++eIt) != eBackIt ) + --eBackIt; + } + } + for ( eIt = edges.begin(); eIt != edges.end(); ++eIt ) + eIt->Reverse(); + SHOW_LIST("ATFER REVERSE", edges) + } + + //================================================================================ + /*! + * \brief Check if propagation is possible + * \param theMesh1 - source mesh + * \param theMesh2 - target mesh + * \retval bool - true if possible + */ + //================================================================================ + + bool IsPropagationPossible( SMESH_Mesh* theMesh1, SMESH_Mesh* theMesh2 ) + { + if ( theMesh1 != theMesh2 ) { + TopoDS_Shape mainShape1 = theMesh1->GetMeshDS()->ShapeToMesh(); + TopoDS_Shape mainShape2 = theMesh2->GetMeshDS()->ShapeToMesh(); + return mainShape1.IsSame( mainShape2 ); + } + return true; + } + + //================================================================================ + /*! + * \brief Fix up association of edges in faces by possible propagation + * \param nbEdges - nb of edges in an outer wire + * \param edges1 - edges of one face + * \param edges2 - matching edges of another face + * \param theMesh1 - mesh 1 + * \param theMesh2 - mesh 2 + */ + //================================================================================ + + void FixAssocByPropagation( const int nbEdges, + list< TopoDS_Edge > & edges1, + list< TopoDS_Edge > & edges2, + SMESH_Mesh* theMesh1, + SMESH_Mesh* theMesh2) + { + if ( nbEdges == 2 && IsPropagationPossible( theMesh1, theMesh2 ) ) + { + list< TopoDS_Edge >::iterator eIt2 = ++edges2.begin(); // 2nd edge of the 2nd face + TopoDS_Edge edge2 = + StdMeshers_ProjectionUtils::GetPropagationEdge( theMesh1, *eIt2, edges1.front() ); + if ( !edge2.IsNull() ) // propagation found for the second edge + Reverse( edges2, nbEdges ); + } + } +} + +//======================================================================= +/*! + * \brief Looks for association of all subshapes of two shapes + * \param theShape1 - shape 1 + * \param theMesh1 - mesh built on shape 1 + * \param theShape2 - shape 2 + * \param theMesh2 - mesh built on shape 2 + * \param theAssociation - association map to be filled that may + * contain association of one or two pairs of vertices + * \retval bool - true if association found + */ +//======================================================================= + +bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& theShape1, + SMESH_Mesh* theMesh1, + const TopoDS_Shape& theShape2, + SMESH_Mesh* theMesh2, + TShapeShapeMap & theMap) +{ + if ( theShape1.ShapeType() != theShape2.ShapeType() ) + RETURN_BAD_RESULT("Different shape types"); + + bool bidirect = ( !theShape1.IsSame( theShape2 )); + if ( !theMap.IsEmpty()) + { + switch ( theShape1.ShapeType() ) { + + case TopAbs_EDGE: { + // ---------------------------------------------------------------------- + if ( theMap.Extent() != 2 ) + RETURN_BAD_RESULT("Wrong map extent " << theMap.Extent() ); + TopoDS_Edge edge1 = TopoDS::Edge( theShape1 ); + TopoDS_Edge edge2 = TopoDS::Edge( theShape2 ); + TopoDS_Vertex VV1[2], VV2[2]; + TopExp::Vertices( edge1, VV1[0], VV1[1] ); + TopExp::Vertices( edge2, VV2[0], VV2[1] ); + int i1 = 0, i2 = 0; + if ( theMap.IsBound( VV1[ i1 ] )) i1 = 1; + if ( theMap.IsBound( VV2[ i2 ] )) i2 = 1; + InsertAssociation( VV1[ i1 ], VV2[ i2 ], theMap, bidirect); + return true; + } + + case TopAbs_FACE: { + // ---------------------------------------------------------------------- + TopoDS_Face face1 = TopoDS::Face( theShape1 ); + TopoDS_Face face2 = TopoDS::Face( theShape2 ); + + TopoDS_Vertex VV1[2], VV2[2]; + // find a not closed edge of face1 both vertices of which are associated + int nbEdges = 0; + TopExp_Explorer exp ( face1, TopAbs_EDGE ); + for ( ; VV2[ 1 ].IsNull() && exp.More(); exp.Next(), ++nbEdges ) { + TopExp::Vertices( TopoDS::Edge( exp.Current() ), VV1[0], VV1[1] ); + if ( theMap.IsBound( VV1[0] ) ) { + VV2[ 0 ] = TopoDS::Vertex( theMap( VV1[0] )); + if ( theMap.IsBound( VV1[1] ) && !VV1[0].IsSame( VV1[1] )) + VV2[ 1 ] = TopoDS::Vertex( theMap( VV1[1] )); + } + } + if ( VV2[ 1 ].IsNull() ) { // 2 bound vertices not found + if ( nbEdges > 1 ) { + RETURN_BAD_RESULT("2 bound vertices not found" ); + } else { + VV2[ 1 ] = VV2[ 0 ]; + } + } + list< TopoDS_Edge > edges1, edges2; + int nbE = FindFaceAssociation( face1, VV1, face2, VV2, edges1, edges2 ); + if ( !nbE ) RETURN_BAD_RESULT("FindFaceAssociation() failed"); + FixAssocByPropagation( nbE, edges1, edges2, theMesh1, theMesh2 ); + + list< TopoDS_Edge >::iterator eIt1 = edges1.begin(); + list< TopoDS_Edge >::iterator eIt2 = edges2.begin(); + for ( ; eIt1 != edges1.end(); ++eIt1, ++eIt2 ) + { + InsertAssociation( *eIt1, *eIt2, theMap, bidirect); + VV1[0] = TopExp::FirstVertex( *eIt1, true ); + VV2[0] = TopExp::FirstVertex( *eIt2, true ); + InsertAssociation( VV1[0], VV2[0], theMap, bidirect); + } + return true; + } + + case TopAbs_SHELL: + case TopAbs_SOLID: { + // ---------------------------------------------------------------------- + TopoDS_Vertex VV1[2], VV2[2]; + // find a not closed edge of shape1 both vertices of which are associated + TopoDS_Edge edge1; + TopExp_Explorer exp ( theShape1, TopAbs_EDGE ); + for ( ; VV2[ 1 ].IsNull() && exp.More(); exp.Next() ) { + edge1 = TopoDS::Edge( exp.Current() ); + TopExp::Vertices( edge1 , VV1[0], VV1[1] ); + if ( theMap.IsBound( VV1[0] )) { + VV2[ 0 ] = TopoDS::Vertex( theMap( VV1[0] )); + if ( theMap.IsBound( VV1[1] ) && !VV1[0].IsSame( VV1[1] )) + VV2[ 1 ] = TopoDS::Vertex( theMap( VV1[1] )); + } + } + if ( VV2[ 1 ].IsNull() ) // 2 bound vertices not found + RETURN_BAD_RESULT("2 bound vertices not found" ); + TopoDS_Edge edge2 = GetEdgeByVertices( theMesh2, VV2[ 0 ], VV2[ 1 ]); + if ( edge2.IsNull() ) + RETURN_BAD_RESULT("GetEdgeByVertices() failed"); + + // get a face sharing edge1 + TopoDS_Shape F1, F2, FF2[2]; + TopTools_ListIteratorOfListOfShape ancestIt = theMesh1->GetAncestors( edge1 ); + for ( ; F1.IsNull() && ancestIt.More(); ancestIt.Next() ) + if ( ancestIt.Value().ShapeType() == TopAbs_FACE ) + F1 = ancestIt.Value().Oriented( TopAbs_FORWARD ); + if ( F1.IsNull() ) + RETURN_BAD_RESULT(" Face1 not found"); + + // get 2 faces sharing edge2 + ancestIt = theMesh2->GetAncestors( edge2 ); + for ( int i = 0; FF2[1].IsNull() && ancestIt.More(); ancestIt.Next() ) + if ( ancestIt.Value().ShapeType() == TopAbs_FACE ) + FF2[ i++ ] = ancestIt.Value().Oriented( TopAbs_FORWARD ); + if ( FF2[1].IsNull() ) + RETURN_BAD_RESULT("2 faces not found"); + + // get oriented edge1 and edge2 from F1 and FF2[0] + for ( exp.Init( F1, TopAbs_EDGE ); exp.More(); exp.Next() ) + if ( edge1.IsSame( exp.Current() )) { + edge1 = TopoDS::Edge( exp.Current() ); + break; + } + + for ( exp.Init( FF2[ 0 ], TopAbs_EDGE ); exp.More(); exp.Next() ) + if ( edge2.IsSame( exp.Current() )) { + edge2 = TopoDS::Edge( exp.Current() ); + break; + } + + // compare first vertices of edge1 and edge2 + TopExp::Vertices( edge1, VV1[0], VV1[1], true ); + TopExp::Vertices( edge2, VV2[0], VV2[1], true ); + F2 = FF2[ 0 ]; + if ( !VV1[ 0 ].IsSame( theMap( VV2[ 0 ]))) { + F2 = FF2[ 1 ]; + edge2.Reverse(); + } + + TopTools_MapOfShape boundEdges; + + // association of face subshapes and neighbour faces + list< pair < TopoDS_Face, TopoDS_Edge > > FE1, FE2; + list< pair < TopoDS_Face, TopoDS_Edge > >::iterator fe1, fe2; + FE1.push_back( make_pair( TopoDS::Face( F1 ), edge1 )); + FE2.push_back( make_pair( TopoDS::Face( F2 ), edge2 )); + for ( fe1 = FE1.begin(), fe2 = FE2.begin(); fe1 != FE1.end(); ++fe1, ++fe2 ) + { + const TopoDS_Face& face1 = fe1->first; + if ( theMap.IsBound( face1 ) ) continue; + const TopoDS_Face& face2 = fe2->first; + edge1 = fe1->second; + edge2 = fe2->second; + TopExp::Vertices( edge1, VV1[0], VV1[1], true ); + TopExp::Vertices( edge2, VV2[0], VV2[1], true ); + list< TopoDS_Edge > edges1, edges2; + int nbE = FindFaceAssociation( face1, VV1, face2, VV2, edges1, edges2 ); + if ( !nbE ) RETURN_BAD_RESULT("FindFaceAssociation() failed"); + FixAssocByPropagation( nbE, edges1, edges2, theMesh1, theMesh2 ); + + InsertAssociation( face1, face2, theMap, bidirect); // assoc faces + list< TopoDS_Edge >::iterator eIt1 = edges1.begin(); + list< TopoDS_Edge >::iterator eIt2 = edges2.begin(); + for ( ; eIt1 != edges1.end(); ++eIt1, ++eIt2 ) + { + if ( !boundEdges.Add( *eIt1 )) continue; // already associated + InsertAssociation( *eIt1, *eIt2, theMap, bidirect); // assoc edges + VV1[0] = TopExp::FirstVertex( *eIt1, true ); + VV2[0] = TopExp::FirstVertex( *eIt2, true ); + InsertAssociation( VV1[0], VV2[0], theMap, bidirect); // assoc vertices + + // add adjacent faces to process + TopoDS_Face nextFace1 = GetNextFace( theMesh1, *eIt1, face1 ); + TopoDS_Face nextFace2 = GetNextFace( theMesh2, *eIt2, face2 ); + if ( !nextFace1.IsNull() && !nextFace2.IsNull() ) { + FE1.push_back( make_pair( nextFace1, *eIt1 )); + FE2.push_back( make_pair( nextFace2, *eIt2 )); + } + } + } + return true; + } + default: + RETURN_BAD_RESULT("Unexpected shape type"); + + } // end switch by shape type + } // end case of available initial vertex association + + //---------------------------------------------------------------------- + // NO INITIAL VERTEX ASSOCIATION + //---------------------------------------------------------------------- + + switch ( theShape1.ShapeType() ) { + + case TopAbs_EDGE: { + // ---------------------------------------------------------------------- + TopoDS_Edge edge1 = TopoDS::Edge( theShape1 ); + TopoDS_Edge edge2 = TopoDS::Edge( theShape2 ); + if ( IsPropagationPossible( theMesh1, theMesh2 )) + { + TopoDS_Edge prpEdge = GetPropagationEdge( theMesh1, edge2, edge1 ); + if ( !prpEdge.IsNull() ) + { + TopoDS_Vertex VV1[2], VV2[2]; + TopExp::Vertices( edge1, VV1[0], VV1[1], true ); + TopExp::Vertices( prpEdge, VV2[0], VV2[1], true ); + InsertAssociation( VV1[ 0 ], VV2[ 0 ], theMap, bidirect); + InsertAssociation( VV1[ 1 ], VV2[ 1 ], theMap, bidirect); + if ( VV1[0].IsSame( VV1[1] ) || // one of edges is closed + VV2[0].IsSame( VV2[1] ) ) + { + InsertAssociation( edge1, prpEdge, theMap, bidirect); // insert with a proper orientation + } + return true; // done + } + } + if ( IsClosedEdge( edge1 ) && IsClosedEdge( edge2 )) + { + // TODO: find out a proper orientation (is it possible?) + InsertAssociation( edge1, edge2, theMap, bidirect); // insert with a proper orientation + InsertAssociation( TopExp::FirstVertex(edge1), TopExp::FirstVertex(edge2), + theMap, bidirect); + return true; // done + } + break; // try by vertex closeness + } + + case TopAbs_FACE: { + // ---------------------------------------------------------------------- + if ( IsPropagationPossible( theMesh1, theMesh2 )) // try by propagation in one mesh + { + TopoDS_Face face1 = TopoDS::Face(theShape1); + TopoDS_Face face2 = TopoDS::Face(theShape2); + // get outer edge of theShape1 + TopoDS_Edge edge1 = TopoDS::Edge( OuterShape( face1, TopAbs_EDGE )); + // find out if any edge of face2 is a propagation edge of outer edge1 + for ( TopExp_Explorer exp( face2, TopAbs_EDGE ); exp.More(); exp.Next() ) { + TopoDS_Edge edge2 = TopoDS::Edge( exp.Current() ); + edge2 = GetPropagationEdge( theMesh1, edge2, edge1 ); + if ( !edge2.IsNull() ) // propagation found + { + TopoDS_Vertex VV1[2], VV2[2]; + TopExp::Vertices( edge1, VV1[0], VV1[1], true ); + TopExp::Vertices( edge2, VV2[0], VV2[1], true ); + list< TopoDS_Edge > edges1, edges2; + int nbE = FindFaceAssociation( face1, VV1, face2, VV2, edges1, edges2 ); + if ( !nbE ) RETURN_BAD_RESULT("FindFaceAssociation() failed"); + if ( nbE == 2 ) // only 2 edges + { + // take care of proper association of propagated edges + bool same1 = edge1.IsSame( edges1.front() ); + bool same2 = edge2.IsSame( edges2.front() ); + if ( same1 != same2 ) + Reverse(edges2, nbE); + } + // store association + list< TopoDS_Edge >::iterator eIt1 = edges1.begin(); + list< TopoDS_Edge >::iterator eIt2 = edges2.begin(); + for ( ; eIt1 != edges1.end(); ++eIt1, ++eIt2 ) + { + InsertAssociation( *eIt1, *eIt2, theMap, bidirect); + VV1[0] = TopExp::FirstVertex( *eIt1, true ); + VV2[0] = TopExp::FirstVertex( *eIt2, true ); + InsertAssociation( VV1[0], VV2[0], theMap, bidirect); + } + return true; + } + } + } + break; // try by vertex closeness + } + default:; + } + + // Find association by closeness of vertices + // ------------------------------------------ + + TopTools_IndexedMapOfShape vMap1, vMap2; + TopExp::MapShapes( theShape1, TopAbs_VERTEX, vMap1 ); + TopExp::MapShapes( theShape2, TopAbs_VERTEX, vMap2 ); + + if ( vMap1.Extent() != vMap2.Extent() ) + RETURN_BAD_RESULT("Different nb of vertices"); + + if ( vMap1.Extent() == 1 ) { + InsertAssociation( vMap1(1), vMap2(1), theMap, bidirect); + if ( theShape1.ShapeType() == TopAbs_EDGE ) + return true; + return FindSubShapeAssociation( theShape1, theMesh1, theShape2, theMesh2, theMap); + } + + // Find transformation to make the shapes be of similar size at same location + + Bnd_Box box[2]; + for ( int i = 1; i <= vMap1.Extent(); ++i ) { + box[ 0 ].Add( BRep_Tool::Pnt ( TopoDS::Vertex( vMap1( i )))); + box[ 1 ].Add( BRep_Tool::Pnt ( TopoDS::Vertex( vMap2( i )))); + } + + gp_Pnt gc[2]; // box center + double x0,y0,z0, x1,y1,z1; + box[0].Get( x0,y0,z0, x1,y1,z1 ); + gc[0] = 0.5 * ( gp_XYZ( x0,y0,z0 ) + gp_XYZ( x1,y1,z1 )); + box[1].Get( x0,y0,z0, x1,y1,z1 ); + gc[1] = 0.5 * ( gp_XYZ( x0,y0,z0 ) + gp_XYZ( x1,y1,z1 )); + + // 1 -> 2 + gp_Vec vec01( gc[0], gc[1] ); + double scale = sqrt( box[1].SquareExtent() / box[0].SquareExtent() ); + + // Find 2 closest vertices + + TopoDS_Vertex VV1[2], VV2[2]; + // get 2 linked vertices of shape 1 not belonging to an inner wire of a face + TopoDS_Shape edge = theShape1; + TopExp_Explorer expF( theShape1, TopAbs_FACE ), expE; + for ( ; expF.More(); expF.Next() ) { + edge.Nullify(); + TopoDS_Shape wire = OuterShape( TopoDS::Face( expF.Current() ), TopAbs_WIRE ); + for ( expE.Init( wire, TopAbs_EDGE ); edge.IsNull() && expE.More(); expE.Next() ) + if ( !IsClosedEdge( TopoDS::Edge( expE.Current() ))) + edge = expE.Current(); + if ( !edge.IsNull() ) + break; + } + if ( edge.IsNull() || edge.ShapeType() != TopAbs_EDGE ) + RETURN_BAD_RESULT("Edge not found"); + + TopExp::Vertices( TopoDS::Edge( edge ), VV1[0], VV1[1]); + if ( VV1[0].IsSame( VV1[1] )) + RETURN_BAD_RESULT("Only closed edges"); + + // find vertices closest to 2 linked vertices of shape 1 + for ( int i1 = 0; i1 < 2; ++i1 ) + { + double dist2 = DBL_MAX; + gp_Pnt p1 = BRep_Tool::Pnt( VV1[ i1 ]); + p1.Translate( vec01 ); + p1.Scale( gc[1], scale ); + for ( int i2 = 1; i2 <= vMap2.Extent(); ++i2 ) + { + TopoDS_Vertex V2 = TopoDS::Vertex( vMap2( i2 )); + gp_Pnt p2 = BRep_Tool::Pnt ( V2 ); + double d2 = p1.SquareDistance( p2 ); + if ( d2 < dist2 && !V2.IsSame( VV2[ 0 ])) { + VV2[ i1 ] = V2; dist2 = d2; + } + } + } + + InsertAssociation( VV1[ 0 ], VV2 [ 0 ], theMap, bidirect); + InsertAssociation( VV1[ 1 ], VV2 [ 1 ], theMap, bidirect); + if ( theShape1.ShapeType() == TopAbs_EDGE ) + return true; + + return FindSubShapeAssociation( theShape1, theMesh1, theShape2, theMesh2, theMap ); +} + +//================================================================================ +/*! + * \brief Find association of edges of faces + * \param face1 - face 1 + * \param VV1 - vertices of face 1 + * \param face2 - face 2 + * \param VV2 - vertices of face 2 associated with oned of face 1 + * \param edges1 - out list of edges of face 1 + * \param edges2 - out list of edges of face 2 + * \retval int - nb of edges in an outer wire in a success case, else zero + */ +//================================================================================ + +int StdMeshers_ProjectionUtils::FindFaceAssociation(const TopoDS_Face& face1, + TopoDS_Vertex VV1[2], + const TopoDS_Face& face2, + TopoDS_Vertex VV2[2], + list< TopoDS_Edge > & edges1, + list< TopoDS_Edge > & edges2) +{ + edges1.clear(); + edges2.clear(); + + list< int > nbVInW1, nbVInW2; + if ( SMESH_Block::GetOrderedEdges( face1, VV1[0], edges1, nbVInW1) != + SMESH_Block::GetOrderedEdges( face2, VV2[0], edges2, nbVInW2) ) + RETURN_BAD_RESULT("Different number of wires in faces "); + + if ( nbVInW1.front() != nbVInW2.front() ) + RETURN_BAD_RESULT("Different number of edges in faces: " << + nbVInW1.front() << " != " << nbVInW2.front()); + + // Define if we need to reverse one of wires to make edges in lists match each other + + bool reverse = false; + + list< TopoDS_Edge >::iterator eBackIt; + if ( !VV1[1].IsSame( TopExp::LastVertex( edges1.front(), true ))) { + eBackIt = --edges1.end(); + // check if the second vertex belongs to the first or last edge in the wire + if ( !VV1[1].IsSame( TopExp::FirstVertex( *eBackIt, true ))) { + bool KO = true; // belongs to none + if ( nbVInW1.size() > 1 ) { // several wires + eBackIt = edges1.begin(); + for ( int i = 1; i < nbVInW1.front(); ++i ) ++eBackIt; + KO = !VV1[1].IsSame( TopExp::FirstVertex( *eBackIt, true )); + } + if ( KO ) + RETURN_BAD_RESULT("GetOrderedEdges() failed"); + } + reverse = true; + } + eBackIt = --edges2.end(); + if ( !VV2[1].IsSame( TopExp::LastVertex( edges2.front(), true ))) { + // check if the second vertex belongs to the first or last edge in the wire + if ( !VV2[1].IsSame( TopExp::FirstVertex( *eBackIt, true ))) { + bool KO = true; // belongs to none + if ( nbVInW2.size() > 1 ) { // several wires + eBackIt = edges2.begin(); + for ( int i = 1; i < nbVInW2.front(); ++i ) ++eBackIt; + KO = !VV2[1].IsSame( TopExp::FirstVertex( *eBackIt, true )); + } + if ( KO ) + RETURN_BAD_RESULT("GetOrderedEdges() failed"); + } + reverse = !reverse; + } + if ( reverse ) + { + Reverse( edges2 , nbVInW2.front()); + if (( VV1[1].IsSame( TopExp::LastVertex( edges1.front(), true ))) != + ( VV2[1].IsSame( TopExp::LastVertex( edges2.front(), true )))) + RETURN_BAD_RESULT("GetOrderedEdges() failed"); + } + return nbVInW2.front(); +} + +//======================================================================= +//function : InitVertexAssociation +//purpose : +//======================================================================= + +void StdMeshers_ProjectionUtils::InitVertexAssociation( const SMESH_Hypothesis* theHyp, + TShapeShapeMap & theAssociationMap) +{ + string hypName = theHyp->GetName(); + if ( hypName == "ProjectionSource1D" ) { + const StdMeshers_ProjectionSource1D * hyp = + static_cast( theHyp ); + if ( hyp->HasVertexAssociation() ) { + InsertAssociation( hyp->GetSourceVertex(),hyp->GetTargetVertex(),theAssociationMap); + } + } + else if ( hypName == "ProjectionSource2D" ) { + const StdMeshers_ProjectionSource2D * hyp = + static_cast( theHyp ); + if ( hyp->HasVertexAssociation() ) { + InsertAssociation( hyp->GetSourceVertex(1),hyp->GetTargetVertex(1),theAssociationMap); + InsertAssociation( hyp->GetSourceVertex(2),hyp->GetTargetVertex(2),theAssociationMap); + } + } + else if ( hypName == "ProjectionSource3D" ) { + const StdMeshers_ProjectionSource3D * hyp = + static_cast( theHyp ); + if ( hyp->HasVertexAssociation() ) { + InsertAssociation( hyp->GetSourceVertex(1),hyp->GetTargetVertex(1),theAssociationMap); + InsertAssociation( hyp->GetSourceVertex(2),hyp->GetTargetVertex(2),theAssociationMap); + } + } +} + +//======================================================================= +/*! + * \brief Inserts association theShape1 <-> theShape2 to TShapeShapeMap + * \param theShape1 - shape 1 + * \param theShape2 - shape 2 + * \param theAssociationMap - association map + * \retval bool - true if there was no association for these shapes before + */ +//======================================================================= + +bool StdMeshers_ProjectionUtils::InsertAssociation( const TopoDS_Shape& theShape1, + const TopoDS_Shape& theShape2, + TShapeShapeMap & theAssociationMap, + const bool theBidirectional) +{ + if ( !theShape1.IsNull() && !theShape2.IsNull() ) { + SHOW_VERTEX(theShape1,"Assoc "); + SHOW_VERTEX(theShape2," to "); + bool isNew = ( theAssociationMap.Bind( theShape1, theShape2 )); + if ( theBidirectional ) + theAssociationMap.Bind( theShape2, theShape1 ); + return isNew; + } + return false; +} + +//======================================================================= +//function : IsSubShape +//purpose : +//======================================================================= + +bool StdMeshers_ProjectionUtils::IsSubShape( const TopoDS_Shape& shape, + SMESH_Mesh* aMesh ) +{ + if ( shape.IsNull() || !aMesh ) + return false; + return aMesh->GetMeshDS()->ShapeToIndex( shape ); +} + +//======================================================================= +//function : IsSubShape +//purpose : +//======================================================================= + +bool StdMeshers_ProjectionUtils::IsSubShape( const TopoDS_Shape& shape, + const TopoDS_Shape& mainShape ) +{ + if ( !shape.IsNull() && !mainShape.IsNull() ) + { + for ( TopExp_Explorer exp( mainShape, shape.ShapeType()); + exp.More(); + exp.Next() ) + if ( shape.IsSame( exp.Current() )) + return true; + } + SCRUTE((shape.IsNull())); + SCRUTE((mainShape.IsNull())); + return false; +} + + +//======================================================================= +/*! + * \brief Finds an edge by its vertices in a main shape of the mesh + * \param aMesh - the mesh + * \param V1 - vertex 1 + * \param V2 - vertex 2 + * \retval TopoDS_Edge - found edge + */ +//======================================================================= + +TopoDS_Edge StdMeshers_ProjectionUtils::GetEdgeByVertices( SMESH_Mesh* theMesh, + const TopoDS_Vertex& theV1, + const TopoDS_Vertex& theV2) +{ + if ( theMesh && !theV1.IsNull() && !theV2.IsNull() ) + { + TopTools_ListIteratorOfListOfShape ancestorIt( theMesh->GetAncestors( theV1 )); + for ( ; ancestorIt.More(); ancestorIt.Next() ) + if ( ancestorIt.Value().ShapeType() == TopAbs_EDGE ) + for ( TopExp_Explorer expV ( ancestorIt.Value(), TopAbs_VERTEX ); + expV.More(); + expV.Next() ) + if ( theV2.IsSame( expV.Current() )) + return TopoDS::Edge( ancestorIt.Value() ); + } + return TopoDS_Edge(); +} + +//================================================================================ +/*! + * \brief Return another face sharing an edge + * \param aMesh - mesh + * \param edge - edge + * \param face - face + * \retval TopoDS_Face - found face + */ +//================================================================================ + +TopoDS_Face StdMeshers_ProjectionUtils::GetNextFace( SMESH_Mesh* mesh, + const TopoDS_Edge& edge, + const TopoDS_Face& face) +{ + if ( mesh && !edge.IsNull() && !face.IsNull() ) + { + TopTools_ListIteratorOfListOfShape ancestorIt( mesh->GetAncestors( edge )); + for ( ; ancestorIt.More(); ancestorIt.Next() ) + if ( ancestorIt.Value().ShapeType() == TopAbs_FACE && + !face.IsSame( ancestorIt.Value() )) + return TopoDS::Face( ancestorIt.Value() ); + } + return TopoDS_Face(); + +} + +//================================================================================ +/*! + * \brief Return a propagation edge + * \param aMesh - mesh + * \param theEdge - edge to find by propagation + * \param fromEdge - start edge for propagation + * \retval TopoDS_Edge - found edge + */ +//================================================================================ + +TopoDS_Edge StdMeshers_ProjectionUtils::GetPropagationEdge( SMESH_Mesh* aMesh, + const TopoDS_Edge& theEdge, + const TopoDS_Edge& fromEdge) +{ + SMESH_IndexedMapOfShape aChain; + //aChain.Add(fromEdge); + + // List of edges, added to chain on the previous cycle pass + TopTools_ListOfShape listPrevEdges; + listPrevEdges.Append(fromEdge/*.Oriented( TopAbs_FORWARD )*/); + + // Collect all edges pass by pass + while (listPrevEdges.Extent() > 0) { + // List of edges, added to chain on this cycle pass + TopTools_ListOfShape listCurEdges; + + // Find the next portion of edges + TopTools_ListIteratorOfListOfShape itE (listPrevEdges); + for (; itE.More(); itE.Next()) { + TopoDS_Shape anE = itE.Value(); + + // Iterate on faces, having edge + TopTools_ListIteratorOfListOfShape itA (aMesh->GetAncestors(anE)); + for (; itA.More(); itA.Next()) { + TopoDS_Shape aW = itA.Value(); + + // There are objects of different type among the ancestors of edge + if (aW.ShapeType() == TopAbs_WIRE) { + TopoDS_Shape anOppE; + + BRepTools_WireExplorer aWE (TopoDS::Wire(aW)); + Standard_Integer nb = 1, found = 0; + TopTools_Array1OfShape anEdges (1,4); + for (; aWE.More(); aWE.Next(), nb++) { + if (nb > 4) { + found = 0; + break; + } + anEdges(nb) = aWE.Current(); + if (anEdges(nb).IsSame(anE)) found = nb; + } + + if (nb == 5 && found > 0) { + // Quadrangle face found, get an opposite edge + Standard_Integer opp = found + 2; + if (opp > 4) opp -= 4; + anOppE = anEdges(opp); + + // add anOppE to aChain if ... + if (!aChain.Contains(anOppE)) { // ... anOppE is not in aChain + // Add found edge to the chain oriented so that to + // have it co-directed with a forward MainEdge + TopAbs_Orientation ori = anE.Orientation(); + if ( anEdges(opp).Orientation() == anEdges(found).Orientation() ) + ori = TopAbs::Reverse( ori ); + anOppE.Orientation( ori ); + if ( anOppE.IsSame( theEdge )) + return TopoDS::Edge( anOppE ); + aChain.Add(anOppE); + listCurEdges.Append(anOppE); + } + } // if (nb == 5 && found > 0) + } // if (aF.ShapeType() == TopAbs_WIRE) + } // for (; itF.More(); itF.Next()) + } // for (; itE.More(); itE.Next()) + + listPrevEdges = listCurEdges; + } // while (listPrevEdges.Extent() > 0) + + return TopoDS_Edge(); +} + +//================================================================================ + /*! + * \brief Find corresponding nodes on two faces + * \param face1 - the first face + * \param mesh1 - mesh containing elements on the first face + * \param face2 - the second face + * \param mesh2 - mesh containing elements on the second face + * \param assocMap - map associating subshapes of the faces + * \param node1To2Map - map containing found matching nodes + * \retval bool - is a success + */ +//================================================================================ + +bool StdMeshers_ProjectionUtils:: +FindMatchingNodesOnFaces( const TopoDS_Face& face1, + SMESH_Mesh* mesh1, + const TopoDS_Face& face2, + SMESH_Mesh* mesh2, + const TShapeShapeMap & assocMap, + TNodeNodeMap & node1To2Map) +{ + SMESHDS_Mesh* meshDS1 = mesh1->GetMeshDS(); + SMESHDS_Mesh* meshDS2 = mesh2->GetMeshDS(); + + SMESH_MesherHelper helper1( *mesh1 ); + SMESH_MesherHelper helper2( *mesh2 ); + + // Get corresponding submeshes and roughly check match of meshes + + SMESHDS_SubMesh * SM2 = meshDS2->MeshElements( face2 ); + SMESHDS_SubMesh * SM1 = meshDS1->MeshElements( face1 ); + if ( !SM2 || !SM1 ) + RETURN_BAD_RESULT("Empty submeshes"); + if ( SM2->NbNodes() != SM1->NbNodes() || + SM2->NbElements() != SM1->NbElements() ) + RETURN_BAD_RESULT("Different meshes on corresponding faces " + << meshDS1->ShapeToIndex( face1 ) << " and " + << meshDS2->ShapeToIndex( face2 )); + if ( SM2->NbElements() == 0 ) + RETURN_BAD_RESULT("Empty submeshes"); + + helper1.SetSubShape( face1 ); + helper2.SetSubShape( face2 ); + if ( helper1.HasSeam() != helper2.HasSeam() ) + RETURN_BAD_RESULT("Different faces' geometry"); + + // Data to call SMESH_MeshEditor::FindMatchingNodes(): + + // 1. Nodes of corresponding links: + + // get 2 matching edges, not seam ones + TopoDS_Edge edge1, edge2; + TopExp_Explorer eE( OuterShape( face2, TopAbs_WIRE ), TopAbs_EDGE ); + do { + edge2 = TopoDS::Edge( eE.Current() ); + eE.Next(); + } while ( BRep_Tool::IsClosed( edge2, face2 ) && eE.More()); + if ( !assocMap.IsBound( edge2 )) + RETURN_BAD_RESULT("Association not found for edge " << meshDS2->ShapeToIndex( edge2 )); + edge1 = TopoDS::Edge( assocMap( edge2 )); + if ( !IsSubShape( edge1, face1 )) + RETURN_BAD_RESULT("Wrong association, edge " << meshDS1->ShapeToIndex( edge1 ) << + " isn't a subshape of face " << meshDS1->ShapeToIndex( face1 )); + + // get 2 matching vertices + TopoDS_Shape V2 = TopExp::FirstVertex( TopoDS::Edge( edge2 )); + if ( !assocMap.IsBound( V2 )) + RETURN_BAD_RESULT("Association not found for vertex " << meshDS2->ShapeToIndex( V2 )); + TopoDS_Shape V1 = assocMap( V2 ); + + // nodes on vertices + SMESHDS_SubMesh * vSM1 = meshDS1->MeshElements( V1 ); + SMESHDS_SubMesh * vSM2 = meshDS2->MeshElements( V2 ); + if ( !vSM1 || !vSM2 || vSM1->NbNodes() != 1 || vSM2->NbNodes() != 1 ) + RETURN_BAD_RESULT("Bad node submesh"); + const SMDS_MeshNode* vNode1 = vSM1->GetNodes()->next(); + const SMDS_MeshNode* vNode2 = vSM2->GetNodes()->next(); + + // nodes on edges linked with nodes on vertices + const SMDS_MeshNode* nullNode = 0; + vector< const SMDS_MeshNode*> eNode1( 2, nullNode ); + vector< const SMDS_MeshNode*> eNode2( 2, nullNode ); + int nbNodeToGet = 1; + if ( IsClosedEdge( edge1 ) || IsClosedEdge( edge2 ) ) + nbNodeToGet = 2; + for ( int is2 = 0; is2 < 2; ++is2 ) + { + TopoDS_Edge & edge = is2 ? edge2 : edge1; + SMESHDS_Mesh * smDS = is2 ? meshDS2 : meshDS1; + SMESHDS_SubMesh* edgeSM = smDS->MeshElements( edge ); + // nodes linked with ones on vertices + const SMDS_MeshNode* vNode = is2 ? vNode2 : vNode1; + vector< const SMDS_MeshNode*>& eNode = is2 ? eNode2 : eNode1; + int nbGotNode = 0; + SMDS_ElemIteratorPtr vElem = vNode->GetInverseElementIterator(); + while ( vElem->more() && nbGotNode != nbNodeToGet ) { + const SMDS_MeshElement* elem = vElem->next(); + if ( elem->GetType() == SMDSAbs_Edge && edgeSM->Contains( elem )) + eNode[ nbGotNode++ ] = + ( elem->GetNode(0) == vNode ) ? elem->GetNode(1) : elem->GetNode(0); + } + if ( nbGotNode > 1 ) // sort found nodes by param on edge + { + SMESH_MesherHelper* helper = is2 ? &helper2 : &helper1; + double u0 = helper->GetNodeU( edge, eNode[ 0 ]); + double u1 = helper->GetNodeU( edge, eNode[ 1 ]); + if ( u0 > u1 ) std::swap( eNode[ 0 ], eNode[ 1 ]); + } + if ( nbGotNode == 0 ) + RETURN_BAD_RESULT("Found no nodes on edge " << smDS->ShapeToIndex( edge ) << + " linked to " << vNode ); + } + + // 2. face sets + + set Elems1, Elems2; + for ( int is2 = 0; is2 < 2; ++is2 ) + { + set & elems = is2 ? Elems2 : Elems1; + SMESHDS_SubMesh* sm = is2 ? SM2 : SM1; + SMESH_MesherHelper* helper = is2 ? &helper2 : &helper1; + const TopoDS_Face & face = is2 ? face2 : face1; + SMDS_ElemIteratorPtr eIt = sm->GetElements(); + + if ( !helper->IsSeamShape( is2 ? edge2 : edge1 )) + { + while ( eIt->more() ) elems.insert( eIt->next() ); + } + else + { + // there is only seam edge in a face, i.e. it is a sphere. + // FindMatchingNodes() will not know which way to go from any edge. + // So we ignore all faces having nodes on edges or vertices except + // one of faces sharing current start nodes + + // find a face to keep + const SMDS_MeshElement* faceToKeep = 0; + const SMDS_MeshNode* vNode = is2 ? vNode2 : vNode1; + const SMDS_MeshNode* eNode = is2 ? eNode2[0] : eNode1[0]; + std::map inSet, notInSet; + + const SMDS_MeshElement* f1 = + SMESH_MeshEditor::FindFaceInSet( vNode, eNode, inSet, notInSet ); + if ( !f1 ) RETURN_BAD_RESULT("The first face on seam not found"); + SMESH_MeshEditor::Insert( f1, notInSet ); + + const SMDS_MeshElement* f2 = + SMESH_MeshEditor::FindFaceInSet( vNode, eNode, inSet, notInSet ); + if ( !f2 ) RETURN_BAD_RESULT("The second face on seam not found"); + + // select a face with less UV of vNode + const SMDS_MeshNode* notSeamNode[2] = {0, 0}; + for ( int iF = 0; iF < 2; ++iF ) { + const SMDS_MeshElement* f = ( iF ? f2 : f1 ); + for ( int i = 0; !notSeamNode[ iF ] && i < f->NbNodes(); ++i ) { + const SMDS_MeshNode* node = f->GetNode( i ); + if ( !helper->IsSeamShape( node->GetPosition()->GetShapeId() )) + notSeamNode[ iF ] = node; + } + } + gp_Pnt2d uv1 = helper->GetNodeUV( face, vNode, notSeamNode[0] ); + gp_Pnt2d uv2 = helper->GetNodeUV( face, vNode, notSeamNode[1] ); + if ( uv1.X() + uv1.Y() > uv2.X() + uv2.Y() ) + faceToKeep = f2; + else + faceToKeep = f1; + + // fill elem set + elems.insert( faceToKeep ); + while ( eIt->more() ) { + const SMDS_MeshElement* f = eIt->next(); + int nbNodes = f->NbNodes(); + if ( f->IsQuadratic() ) + nbNodes /= 2; + bool onBnd = false; + for ( int i = 0; !onBnd && i < nbNodes; ++i ) { + const SMDS_MeshNode* node = f->GetNode( i ); + onBnd = ( node->GetPosition()->GetTypeOfPosition() != SMDS_TOP_FACE); + } + if ( !onBnd ) + elems.insert( f ); + } + } // case on a sphere + } // loop on 2 faces + + node1To2Map.clear(); + int res = SMESH_MeshEditor::FindMatchingNodes( Elems1, Elems2, + vNode1, vNode2, + eNode1[0], eNode2[0], + node1To2Map); + if ( res != SMESH_MeshEditor::SEW_OK ) + RETURN_BAD_RESULT("FindMatchingNodes() result " << res ); + + + // On a sphere, add matching nodes on the edge + + if ( helper1.IsSeamShape( edge1 )) + { + // sort nodes on edges by param on edge + map< double, const SMDS_MeshNode* > u2nodesMaps[2]; + for ( int is2 = 0; is2 < 2; ++is2 ) + { + TopoDS_Edge & edge = is2 ? edge2 : edge1; + SMESHDS_Mesh * smDS = is2 ? meshDS2 : meshDS1; + SMESHDS_SubMesh* edgeSM = smDS->MeshElements( edge ); + map< double, const SMDS_MeshNode* > & pos2nodes = u2nodesMaps[ is2 ]; + + SMDS_NodeIteratorPtr nIt = edgeSM->GetNodes(); + while ( nIt->more() ) { + const SMDS_MeshNode* node = nIt->next(); + const SMDS_EdgePosition* pos = + static_cast(node->GetPosition().get()); + pos2nodes.insert( make_pair( pos->GetUParameter(), node )); + } + if ( pos2nodes.size() != edgeSM->NbNodes() ) + RETURN_BAD_RESULT("Equal params of nodes on edge " + << smDS->ShapeToIndex( edge ) << " of face " << is2 ); + } + if ( u2nodesMaps[0].size() != u2nodesMaps[1].size() ) + RETURN_BAD_RESULT("Different nb of new nodes on edges or wrong params"); + + // compare edge orientation + double u1 = helper1.GetNodeU( edge1, vNode1 ); + double u2 = helper2.GetNodeU( edge2, vNode2 ); + bool isFirst1 = ( u1 < u2nodesMaps[0].begin()->first ); + bool isFirst2 = ( u2 < u2nodesMaps[1].begin()->first ); + bool reverse ( isFirst1 != isFirst2 ); + + // associate matching nodes + map< double, const SMDS_MeshNode* >::iterator u_Node1, u_Node2, end1; + map< double, const SMDS_MeshNode* >::reverse_iterator uR_Node2; + u_Node1 = u2nodesMaps[0].begin(); + u_Node2 = u2nodesMaps[1].begin(); + uR_Node2 = u2nodesMaps[1].rbegin(); + end1 = u2nodesMaps[0].end(); + for ( ; u_Node1 != end1; ++u_Node1 ) { + const SMDS_MeshNode* n1 = u_Node1->second; + const SMDS_MeshNode* n2 = ( reverse ? (uR_Node2++)->second : (u_Node2++)->second ); + node1To2Map.insert( make_pair( n1, n2 )); + } + + // associate matching nodes on the last vertices + V2 = TopExp::LastVertex( TopoDS::Edge( edge2 )); + if ( !assocMap.IsBound( V2 )) + RETURN_BAD_RESULT("Association not found for vertex " << meshDS2->ShapeToIndex( V2 )); + V1 = assocMap( V2 ); + vSM1 = meshDS1->MeshElements( V1 ); + vSM2 = meshDS2->MeshElements( V2 ); + if ( !vSM1 || !vSM2 || vSM1->NbNodes() != 1 || vSM2->NbNodes() != 1 ) + RETURN_BAD_RESULT("Bad node submesh"); + vNode1 = vSM1->GetNodes()->next(); + vNode2 = vSM2->GetNodes()->next(); + node1To2Map.insert( make_pair( vNode1, vNode2 )); + } + + return true; +} + +//================================================================================ +/*! + * \brief Check if the first and last vertices of an edge are the same + * \param anEdge - the edge to check + * \retval bool - true if same + */ +//================================================================================ + +bool StdMeshers_ProjectionUtils::IsClosedEdge( const TopoDS_Edge& anEdge ) +{ + return TopExp::FirstVertex( anEdge ).IsSame( TopExp::LastVertex( anEdge )); +} + +//================================================================================ + /*! + * \brief Return any subshape of a face belonging to the outer wire + * \param face - the face + * \param type - type of subshape to return + * \retval TopoDS_Shape - the found subshape + */ +//================================================================================ + +TopoDS_Shape StdMeshers_ProjectionUtils::OuterShape( const TopoDS_Face& face, + TopAbs_ShapeEnum type) +{ + TopExp_Explorer exp( BRepTools::OuterWire( face ), type ); + if ( exp.More() ) + return exp.Current(); + return TopoDS_Shape(); +} + +//================================================================================ + /*! + * \brief Check that submeshis is computed and try to compute it if is not + * \param sm - submesh to compute + * \param iterationNb - int used to stop infinite recursive call + * \retval bool - true if computed + */ +//================================================================================ + +bool StdMeshers_ProjectionUtils::MakeComputed(SMESH_subMesh * sm, const int iterationNb) +{ + if ( iterationNb > 10 ) + RETURN_BAD_RESULT("Infinite recursive projection"); + if ( !sm ) + RETURN_BAD_RESULT("NULL submesh"); + if ( sm->IsMeshComputed() ) + return true; + + SMESH_Mesh* mesh = sm->GetFather(); + SMESH_Gen* gen = mesh->GetGen(); + SMESH_Algo* algo = gen->GetAlgo( *mesh, sm->GetSubShape() ); + if ( !algo ) + RETURN_BAD_RESULT("No algo assigned to submesh " << sm->GetId()); + + string algoType = algo->GetName(); + if ( algoType.substr(0, 11) != "Projection_") + return gen->Compute( *mesh, sm->GetSubShape() ); + + // try to compute source mesh + + const list & hyps = + algo->GetUsedHypothesis( *mesh, sm->GetSubShape() ); + + TopoDS_Shape srcShape; + SMESH_Mesh* srcMesh = 0; + list ::const_iterator hIt = hyps.begin(); + for ( ; srcShape.IsNull() && hIt != hyps.end(); ++hIt ) { + string hypName = (*hIt)->GetName(); + if ( hypName == "ProjectionSource1D" ) { + const StdMeshers_ProjectionSource1D * hyp = + static_cast( *hIt ); + srcShape = hyp->GetSourceEdge(); + srcMesh = hyp->GetSourceMesh(); + } + else if ( hypName == "ProjectionSource2D" ) { + const StdMeshers_ProjectionSource2D * hyp = + static_cast( *hIt ); + srcShape = hyp->GetSourceFace(); + srcMesh = hyp->GetSourceMesh(); + } + else if ( hypName == "ProjectionSource3D" ) { + const StdMeshers_ProjectionSource3D * hyp = + static_cast( *hIt ); + srcShape = hyp->GetSource3DShape(); + srcMesh = hyp->GetSourceMesh(); + } + } + if ( srcShape.IsNull() ) // no projection source defined + return gen->Compute( *mesh, sm->GetSubShape() ); + + if ( srcShape.IsSame( sm->GetSubShape() )) + RETURN_BAD_RESULT("Projection from self"); + + if ( !srcMesh ) + srcMesh = mesh; + + return MakeComputed( srcMesh->GetSubMesh( srcShape ), iterationNb + 1 ); +} + +//================================================================================ + /*! + * \brief Count nb of subshapes + * \param shape - the shape + * \param type - the type of subshapes to count + * \retval int - the calculated number + */ +//================================================================================ + +int StdMeshers_ProjectionUtils::Count(const TopoDS_Shape& shape, + const TopAbs_ShapeEnum type, + const bool ignoreSame) +{ + if ( ignoreSame ) { + TopTools_IndexedMapOfShape map; + TopExp::MapShapes( shape, type, map ); + return map.Extent(); + } + else { + int nb = 0; + for ( TopExp_Explorer exp( shape, type ); exp.More(); exp.Next() ) + ++nb; + return nb; + } +} + + // bull shit +// Standard_Real f1,l1, f2,l2; +// BRep_Tool::Range( edge1, f1,l1 ); +// BRep_Tool::Range( edge2, f2,l2 ); +// BRepAdaptor_Curve e1( edge1 ), e2( edge2 ); +// gp_Pnt pf1, pf2; +// gp_Vec dirX1, dirX2; // 1st derivatives +// e1.D1( f1, pf1, dirX1 ); +// e2.D1( f2, pf2, dirX2 ); +// gp_Pnt pm1 = e1.Value( 0.5 * ( f1 + l1 )); +// gp_Pnt pm2 = e2.Value( 0.5 * ( f2 + l2 )); +// gp_Vec dirZ1( pf1, pm1 ), dirZ2( pf2, pm2 ); +// gp_Trsf trsf; +// gp_Ax3 fromSys( pf1, dirZ1, dirX1 ), toSys( pf2, dirZ2, dirX2 ); +// trsf.SetTransformation( fromSys, toSys ); +// dirX1.Transform( trsf ); +// bool reverse = ( dirX1 * dirX2 < 0 ); +// if ( reverse ) edge2.Reverse(); diff --git a/src/StdMeshers/StdMeshers_ProjectionUtils.hxx b/src/StdMeshers/StdMeshers_ProjectionUtils.hxx new file mode 100644 index 000000000..52d11dc2c --- /dev/null +++ b/src/StdMeshers/StdMeshers_ProjectionUtils.hxx @@ -0,0 +1,198 @@ +// SMESH SMESH : idl implementation based on 'SMESH' unit's calsses +// +// Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// +// +// File : StdMeshers_ProjectionUtils.hxx +// Created : Thu Oct 26 15:37:24 2006 +// Author : Edward AGAPOV (eap) + + +#ifndef StdMeshers_ProjectionUtils_HeaderFile +#define StdMeshers_ProjectionUtils_HeaderFile + +#include +#include +#include +#include + +#include +#include + +class TopoDS_Shape; +class SMDS_MeshNode; +class SMESH_Mesh; +class SMESH_Hypothesis; +class SMESH_subMesh; + +/*! + * \brief Class encapsulating methods common to Projection algorithms + */ +class StdMeshers_ProjectionUtils +{ + public: + + typedef TopTools_DataMapOfShapeShape TShapeShapeMap; + typedef std::map TNodeNodeMap; + + /*! + * \brief Looks for association of all subshapes of two shapes + * \param theShape1 - shape 1 + * \param theMesh1 - mesh built on shape 1 + * \param theShape2 - shape 2 + * \param theMesh2 - mesh built on shape 2 + * \param theAssociation - association map to be filled that may + * contain association of one or two pairs of vertices + * \retval bool - true if association found + */ + static bool FindSubShapeAssociation(const TopoDS_Shape& theShape1, + SMESH_Mesh* theMesh1, + const TopoDS_Shape& theShape2, + SMESH_Mesh* theMesh2, + TShapeShapeMap & theAssociationMap); + + /*! + * \brief Find association of edges of faces + * \param face1 - face 1 + * \param VV1 - vertices of face 1 + * \param face2 - face 2 + * \param VV2 - vertices of face 2 associated with oned of face 1 + * \param edges1 - out list of edges of face 1 + * \param edges2 - out list of edges of face 2 + * \retval int - nb of edges in an outer wire in a success case, else zero + */ + static int FindFaceAssociation(const TopoDS_Face& face1, + TopoDS_Vertex VV1[2], + const TopoDS_Face& face2, + TopoDS_Vertex VV2[2], + list< TopoDS_Edge > & edges1, + list< TopoDS_Edge > & edges2); + + /*! + * \brief Insert vertex association defined by a hypothesis into a map + * \param theHyp - hypothesis + * \param theAssociationMap - association map + */ + static void InitVertexAssociation( const SMESH_Hypothesis* theHyp, + TShapeShapeMap & theAssociationMap); + + /*! + * \brief Inserts association theShape1 <-> theShape2 to TShapeShapeMap + * \param theShape1 - shape 1 + * \param theShape2 - shape 2 + * \param theAssociationMap - association map + * \param theBidirectional - if false, inserts theShape1 -> theShape2 association + * \retval bool - true if there was no association for these shapes before + */ + static bool InsertAssociation( const TopoDS_Shape& theShape1, + const TopoDS_Shape& theShape2, + TShapeShapeMap & theAssociationMap, + const bool theBidirectional=true); + + static bool IsSubShape( const TopoDS_Shape& shape, SMESH_Mesh* aMesh ); + + static bool IsSubShape( const TopoDS_Shape& shape, const TopoDS_Shape& mainShape ); + + /*! + * \brief Finds an edge by its vertices in a main shape of the mesh + * \param aMesh - the mesh + * \param V1 - vertex 1 + * \param V2 - vertex 2 + * \retval TopoDS_Edge - found edge + */ + static TopoDS_Edge GetEdgeByVertices( SMESH_Mesh* aMesh, + const TopoDS_Vertex& V1, + const TopoDS_Vertex& V2); + + /*! + * \brief Return another face sharing an edge + * \param aMesh - mesh + * \param edge - edge + * \param face - face + * \retval TopoDS_Face - found face + */ + static TopoDS_Face GetNextFace( SMESH_Mesh* aMesh, + const TopoDS_Edge& edge, + const TopoDS_Face& face); + + /*! + * \brief Return an oriented propagation edge + * \param aMesh - mesh + * \param fromEdge - start edge for propagation + * \retval TopoDS_Edge - found edge + */ + static TopoDS_Edge GetPropagationEdge( SMESH_Mesh* aMesh, + const TopoDS_Edge& anEdge, + const TopoDS_Edge& fromEdge); + + /*! + * \brief Find corresponding nodes on two faces + * \param face1 - the first face + * \param mesh1 - mesh containing elements on the first face + * \param face2 - the second face + * \param mesh2 - mesh containing elements on the second face + * \param assocMap - map associating subshapes of the faces + * \param nodeIn2OutMap - map containing found matching nodes + * \retval bool - is a success + */ + static bool FindMatchingNodesOnFaces( const TopoDS_Face& face1, + SMESH_Mesh* mesh1, + const TopoDS_Face& face2, + SMESH_Mesh* mesh2, + const TShapeShapeMap & assocMap, + TNodeNodeMap & nodeIn2OutMap); + /*! + * \brief Check if the first and last vertices of an edge are the same + * \param anEdge - the edge to check + * \retval bool - true if same + */ + static bool IsClosedEdge( const TopoDS_Edge& anEdge ); + + /*! + * \brief Return any subshape of a face belonging to the outer wire + * \param face - the face + * \param type - type of subshape to return + * \retval TopoDS_Shape - the found subshape + */ + static TopoDS_Shape OuterShape( const TopoDS_Face& face, + TopAbs_ShapeEnum type); + + /*! + * \brief Check that submeshis is computed and try to compute it if is not + * \param sm - submesh to compute + * \param iterationNb - int used to stop infinite recursive call + * \retval bool - true if computed + */ + static bool MakeComputed(SMESH_subMesh * sm, const int iterationNb = 0); + + /*! + * \brief Count nb of subshapes + * \param shape - the shape + * \param type - the type of subshapes to count + * \param ignoreSame - if true, use map not to count same shapes, esle use explorer + * \retval int - the calculated number + */ + static int Count(const TopoDS_Shape& shape, + const TopAbs_ShapeEnum type, + const bool ignoreSame); +}; + +#endif diff --git a/src/StdMeshers/StdMeshers_Projection_1D.cxx b/src/StdMeshers/StdMeshers_Projection_1D.cxx new file mode 100644 index 000000000..acf89664b --- /dev/null +++ b/src/StdMeshers/StdMeshers_Projection_1D.cxx @@ -0,0 +1,362 @@ +// SMESH SMESH : implementaion of SMESH idl descriptions +// +// Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// +// +// File : StdMeshers_Projection_1D.cxx +// Module : SMESH +// Created : Fri Oct 20 11:37:07 2006 +// Author : Edward AGAPOV (eap) + + +#include "StdMeshers_Projection_1D.hxx" + +#include "StdMeshers_ProjectionSource1D.hxx" +#include "StdMeshers_ProjectionUtils.hxx" + +#include "SMDS_MeshNode.hxx" +#include "SMDS_MeshElement.hxx" +#include "SMESHDS_Mesh.hxx" +#include "SMESHDS_SubMesh.hxx" +#include "SMESH_Mesh.hxx" +#include "SMESH_MesherHelper.hxx" +#include "SMESH_subMesh.hxx" +#include "SMESH_subMeshEventListener.hxx" +#include "SMESH_Gen.hxx" + +#include +#include +#include +#include +#include + +#include "utilities.h" + + +using namespace std; + +#define RETURN_BAD_RESULT(msg) { MESSAGE(msg); return false; } + +typedef StdMeshers_ProjectionUtils TAssocTool; + +//======================================================================= +//function : StdMeshers_Projection_1D +//purpose : +//======================================================================= + +StdMeshers_Projection_1D::StdMeshers_Projection_1D(int hypId, int studyId, SMESH_Gen* gen) + :SMESH_1D_Algo(hypId, studyId, gen) +{ + _name = "Projection_1D"; + _shapeType = (1 << TopAbs_EDGE); // 1 bit per shape type + + _compatibleHypothesis.push_back("ProjectionSource1D"); + _sourceHypo = 0; +} + +//================================================================================ +/*! + * \brief Destructor + */ +//================================================================================ + +StdMeshers_Projection_1D::~StdMeshers_Projection_1D() +{} + +//======================================================================= +//function : CheckHypothesis +//purpose : +//======================================================================= + +bool StdMeshers_Projection_1D::CheckHypothesis(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + SMESH_Hypothesis::Hypothesis_Status& aStatus) +{ + _sourceHypo = 0; + list ::const_iterator itl; + + const list &hyps = GetUsedHypothesis(aMesh, aShape); + if ( hyps.size() == 0 ) + { + aStatus = SMESH_Hypothesis::HYP_MISSING; + return false; // can't work with no hypothesis + } + + if ( hyps.size() > 1 ) + { + aStatus = SMESH_Hypothesis::HYP_ALREADY_EXIST; + return false; + } + + const SMESHDS_Hypothesis *theHyp = hyps.front(); + + string hypName = theHyp->GetName(); + + aStatus = SMESH_Hypothesis::HYP_OK; + + if (hypName == "ProjectionSource1D") + { + _sourceHypo = static_cast(theHyp); + + // Check hypo parameters + + SMESH_Mesh* srcMesh = _sourceHypo->GetSourceMesh(); + SMESH_Mesh* tgtMesh = & aMesh; + if ( !srcMesh ) + srcMesh = tgtMesh; + + // check vertices + if ( _sourceHypo->HasVertexAssociation() ) + { + // source and target vertices + if ( !TAssocTool::IsSubShape( _sourceHypo->GetSourceVertex(), srcMesh ) || + !TAssocTool::IsSubShape( _sourceHypo->GetTargetVertex(), tgtMesh ) || + !TAssocTool::IsSubShape( _sourceHypo->GetTargetVertex(), aShape ) || + !TAssocTool::IsSubShape( _sourceHypo->GetSourceVertex(), + _sourceHypo->GetSourceEdge() )) + aStatus = SMESH_Hypothesis::HYP_BAD_PARAMETER; + } + // check source edge + if ( !TAssocTool::IsSubShape( _sourceHypo->GetSourceEdge(), srcMesh )) + aStatus = SMESH_Hypothesis::HYP_BAD_PARAMETER; + } + else + { + aStatus = SMESH_Hypothesis::HYP_INCOMPATIBLE; + } + return ( aStatus == HYP_OK ); +} + +//======================================================================= +//function : Compute +//purpose : +//======================================================================= + +bool StdMeshers_Projection_1D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theShape) +{ + if ( !_sourceHypo ) + return false; + + TopoDS_Edge tgtEdge = TopoDS::Edge( theShape.Oriented(TopAbs_FORWARD)); + TopoDS_Edge srcEdge = TopoDS::Edge( _sourceHypo->GetSourceEdge().Oriented(TopAbs_FORWARD)); + + TopoDS_Vertex tgtV[2], srcV[2]; + TopExp::Vertices( tgtEdge, tgtV[0], tgtV[1] ); + TopExp::Vertices( srcEdge, srcV[0], srcV[1] ); + + SMESH_Mesh * srcMesh = _sourceHypo->GetSourceMesh(); + SMESH_Mesh * tgtMesh = & theMesh; + if ( !srcMesh ) + srcMesh = tgtMesh; + + SMESHDS_Mesh * meshDS = theMesh.GetMeshDS(); + + // --------------------------- + // Make subshapes association + // --------------------------- + + TAssocTool::TShapeShapeMap shape2ShapeMap; + TAssocTool::InitVertexAssociation( _sourceHypo, shape2ShapeMap ); + if ( !TAssocTool::FindSubShapeAssociation( tgtEdge, tgtMesh, srcEdge, srcMesh, + shape2ShapeMap) ) + RETURN_BAD_RESULT("FindSubShapeAssociation failed"); + + // ---------------------------------------------- + // Assure that mesh on a source edge is computed + // ---------------------------------------------- + + SMESH_subMesh* srcSubMesh = srcMesh->GetSubMesh( srcEdge ); + //SMESH_subMesh* tgtSubMesh = tgtMesh->GetSubMesh( tgtEdge ); + + if ( tgtMesh == srcMesh ) { + if ( !TAssocTool::MakeComputed( srcSubMesh )) + RETURN_BAD_RESULT("Impossible to compute the source mesh"); + } + else { + if ( !srcSubMesh->IsMeshComputed() ) + RETURN_BAD_RESULT("Source mesh is not computed"); + } + // ----------------------------------------------- + // Find out nodes distribution on the source edge + // ----------------------------------------------- + + double srcLength = EdgeLength( srcEdge ); + double tgtLength = EdgeLength( tgtEdge ); + + vector< double > params; // sorted parameters of nodes on the source edge + if ( !SMESH_Algo::GetNodeParamOnEdge( srcMesh->GetMeshDS(), srcEdge, params )) + RETURN_BAD_RESULT("Bad node params on the source edge"); + + int i, nbNodes = params.size(); + + vector< double > lengths( nbNodes - 1 ); // lengths of segments of the source edge + if ( srcLength > 0 ) + { + BRepAdaptor_Curve curveAdaptor( srcEdge ); + for ( i = 1; i < nbNodes; ++i ) + lengths[ i-1 ] = GCPnts_AbscissaPoint::Length( curveAdaptor, params[i-1], params[i]); + } + else // degenerated source edge + { + for ( i = 1; i < nbNodes; ++i ) + lengths[ i-1 ] = params[i] - params[i-1]; + srcLength = params.back() - params[0]; + } + + bool reverse = ( srcV[0].IsSame( shape2ShapeMap( tgtV[1] ))); + if ( shape2ShapeMap.IsBound( tgtEdge )) // case of closed edge + reverse = ( shape2ShapeMap( tgtEdge ).Orientation() == TopAbs_REVERSED ); + if ( reverse ) // reverse lengths of segments + std::reverse( lengths.begin(), lengths.end() ); + + // ---------- + // Make mesh + // ---------- + + // vector of target nodes + vector< const SMDS_MeshNode* > nodes ( nbNodes ); + + // Get the first and last nodes + // ----------------------------- + + SMESHDS_SubMesh* smV0 = meshDS->MeshElements( tgtV[0] ); + SMESHDS_SubMesh* smV1 = meshDS->MeshElements( tgtV[1] ); + if ( !smV0 || !smV1 ) + RETURN_BAD_RESULT("No submeshes on vertices"); + + SMDS_NodeIteratorPtr nItV0 = smV0->GetNodes(); + SMDS_NodeIteratorPtr nItV1 = smV1->GetNodes(); + if ( !nItV0->more() || !nItV1->more() ) + RETURN_BAD_RESULT("No nodes on vertices"); + + nodes.front() = nItV0->next(); + nodes.back() = nItV1->next(); + + // Compute parameters on the target edge and make internal nodes + // -------------------------------------------------------------- + + vector< double > tgtParams( nbNodes ); + + BRep_Tool::Range( tgtEdge, tgtParams.front(), tgtParams.back() ); + if ( tgtLength <= 0 ) + tgtLength = tgtParams.back() - tgtParams.front(); + double dl = tgtLength / srcLength; + + if ( tgtLength > 0 ) + { + BRepAdaptor_Curve curveAdaptor( tgtEdge ); + + // compute params on internal nodes + for ( i = 1; i < nbNodes - 1; ++i ) + { + // computes a point on a at the given distance + // from the point at given parameter. + GCPnts_AbscissaPoint Discret( curveAdaptor, dl * lengths[ i-1 ], tgtParams[ i-1 ] ); + if ( !Discret.IsDone() ) + RETURN_BAD_RESULT(" GCPnts_AbscissaPoint failed"); + tgtParams[ i ] = Discret.Parameter(); + } + // make internal nodes + for ( i = 1; i < nbNodes - 1; ++i ) + { + gp_Pnt P = curveAdaptor.Value( tgtParams[ i ]); + SMDS_MeshNode* node = meshDS->AddNode(P.X(), P.Y(), P.Z()); + meshDS->SetNodeOnEdge( node, tgtEdge, tgtParams[ i ]); + nodes[ i ] = node; + } + } + else // degenerated target edge + { + // compute params and make internal nodes + gp_Pnt P = BRep_Tool::Pnt( tgtV[0] ); + + for ( i = 1; i < nbNodes - 1; ++i ) + { + SMDS_MeshNode* node = meshDS->AddNode(P.X(), P.Y(), P.Z()); + tgtParams[ i ] = tgtParams[ i-1 ] + dl * lengths[ i-1 ]; + meshDS->SetNodeOnEdge( node, tgtEdge, tgtParams[ i ]); + nodes[ i ] = node; + } + } + + // Quadratic mesh? + // ---------------- + + bool quadratic = false; + SMDS_ElemIteratorPtr elemIt = srcSubMesh->GetSubMeshDS()->GetElements(); + if ( elemIt->more() ) + quadratic = elemIt->next()->IsQuadratic(); + else { + SMDS_NodeIteratorPtr nodeIt = srcSubMesh->GetSubMeshDS()->GetNodes(); + while ( nodeIt->more() && !quadratic ) + quadratic = SMESH_MesherHelper::IsMedium( nodeIt->next() ); + } + // enough nodes to make all edges quadratic? + if ( quadratic && ( nbNodes < 3 || ( nbNodes % 2 != 1 ))) + RETURN_BAD_RESULT("Wrong nb nodes to make quadratic mesh"); + + // Create edges + // ------------- + + SMDS_MeshElement* edge = 0; + int di = quadratic ? 2 : 1; + for ( i = di; i < nbNodes; i += di) + { + if ( quadratic ) + edge = meshDS->AddEdge( nodes[i-2], nodes[i], nodes[i-1] ); + else + edge = meshDS->AddEdge( nodes[i-1], nodes[i] ); + meshDS->SetMeshElementOnShape(edge, tgtEdge ); + } + + return true; +} + +//============================================================================= +/*! + * \brief Sets a default event listener to submesh of the source edge + * \param subMesh - submesh where algo is set + * + * This method is called when a submesh gets HYP_OK algo_state. + * After being set, event listener is notified on each event of a submesh. + * Arranges that CLEAN event is translated from source submesh to + * the submesh + */ +//============================================================================= + +void StdMeshers_Projection_1D::SetEventListener(SMESH_subMesh* subMesh) +{ + if ( _sourceHypo && ! _sourceHypo->GetSourceEdge().IsNull() ) + { + SMESH_Mesh* srcMesh = _sourceHypo->GetSourceMesh(); + if ( !srcMesh ) + srcMesh = subMesh->GetFather(); + + SMESH_subMesh* srcEdgeSM = + srcMesh->GetSubMesh( _sourceHypo->GetSourceEdge() ); + + if ( srcEdgeSM != subMesh ) + subMesh->SetEventListener( new SMESH_subMeshEventListener(), + SMESH_subMeshEventListenerData::MakeData( subMesh ), + srcEdgeSM ); + } +} + diff --git a/src/StdMeshers/StdMeshers_Projection_1D.hxx b/src/StdMeshers/StdMeshers_Projection_1D.hxx new file mode 100644 index 000000000..31345809d --- /dev/null +++ b/src/StdMeshers/StdMeshers_Projection_1D.hxx @@ -0,0 +1,64 @@ +// SMESH SMESH : implementaion of SMESH idl descriptions +// +// Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// +// +// File : StdMeshers_Projection_1D.hxx +// Module : SMESH + +#ifndef _SMESH_Projection_1D_HXX_ +#define _SMESH_Projection_1D_HXX_ + +#include "SMESH_1D_Algo.hxx" + + +class StdMeshers_ProjectionSource1D; + +class StdMeshers_Projection_1D: public SMESH_1D_Algo +{ +public: + StdMeshers_Projection_1D(int hypId, int studyId, SMESH_Gen* gen); + virtual ~StdMeshers_Projection_1D(); + + virtual bool CheckHypothesis(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + SMESH_Hypothesis::Hypothesis_Status& aStatus); + + virtual bool Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape); + + /*! + * \brief Sets a default event listener to submesh of the source edge + * \param whenSetToSubMesh - submesh where algo is set + * + * After being set, event listener is notified on each event of a submesh. + * This method is called when a submesh gets HYP_OK algo_state. + * Arranges that CLEAN event is translated from source submesh to + * the whenSetToSubMesh submesh. + */ + virtual void SetEventListener(SMESH_subMesh* whenSetToSubMesh); + +protected: + + const StdMeshers_ProjectionSource1D* _sourceHypo; + +}; + +#endif diff --git a/src/StdMeshers/StdMeshers_Projection_2D.cxx b/src/StdMeshers/StdMeshers_Projection_2D.cxx new file mode 100644 index 000000000..5e10f6d07 --- /dev/null +++ b/src/StdMeshers/StdMeshers_Projection_2D.cxx @@ -0,0 +1,638 @@ +// SMESH SMESH : implementaion of SMESH idl descriptions +// +// Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// +// +// File : StdMeshers_Projection_2D.cxx +// Module : SMESH +// Created : Fri Oct 20 11:37:07 2006 +// Author : Edward AGAPOV (eap) + + +#include "StdMeshers_Projection_2D.hxx" + +#include "StdMeshers_ProjectionSource2D.hxx" +#include "StdMeshers_ProjectionUtils.hxx" + +#include "SMESHDS_Hypothesis.hxx" +#include "SMESHDS_SubMesh.hxx" +#include "SMESH_Block.hxx" +#include "SMESH_Gen.hxx" +#include "SMESH_Mesh.hxx" +#include "SMESH_MeshEditor.hxx" +#include "SMESH_Pattern.hxx" +#include "SMESH_subMesh.hxx" +#include "SMESH_subMeshEventListener.hxx" +#include "SMDS_EdgePosition.hxx" + +#include "utilities.h" + +#include +#include +#include +#include + + + +using namespace std; + +#define RETURN_BAD_RESULT(msg) { MESSAGE(msg); return false; } + +typedef StdMeshers_ProjectionUtils TAssocTool; + +//======================================================================= +//function : StdMeshers_Projection_2D +//purpose : +//======================================================================= + +StdMeshers_Projection_2D::StdMeshers_Projection_2D(int hypId, int studyId, SMESH_Gen* gen) + :SMESH_2D_Algo(hypId, studyId, gen) +{ + _name = "Projection_2D"; + _shapeType = (1 << TopAbs_FACE); // 1 bit per shape type + + _compatibleHypothesis.push_back("ProjectionSource2D"); + _sourceHypo = 0; +} + +//================================================================================ +/*! + * \brief Destructor + */ +//================================================================================ + +StdMeshers_Projection_2D::~StdMeshers_Projection_2D() +{} + +//======================================================================= +//function : CheckHypothesis +//purpose : +//======================================================================= + +bool StdMeshers_Projection_2D::CheckHypothesis(SMESH_Mesh& theMesh, + const TopoDS_Shape& theShape, + SMESH_Hypothesis::Hypothesis_Status& theStatus) +{ + list ::const_iterator itl; + + const list &hyps = GetUsedHypothesis(theMesh, theShape); + if ( hyps.size() == 0 ) + { + theStatus = HYP_MISSING; + return false; // can't work with no hypothesis + } + + if ( hyps.size() > 1 ) + { + theStatus = HYP_ALREADY_EXIST; + return false; + } + + const SMESHDS_Hypothesis *theHyp = hyps.front(); + + string hypName = theHyp->GetName(); + + theStatus = HYP_OK; + + if (hypName == "ProjectionSource2D") + { + _sourceHypo = static_cast(theHyp); + + // Check hypo parameters + + SMESH_Mesh* srcMesh = _sourceHypo->GetSourceMesh(); + SMESH_Mesh* tgtMesh = & theMesh; + if ( !srcMesh ) + srcMesh = tgtMesh; + + // check vertices + if ( _sourceHypo->HasVertexAssociation() ) + { + // source vertices + TopoDS_Shape edge = TAssocTool::GetEdgeByVertices + ( srcMesh, _sourceHypo->GetSourceVertex(1), _sourceHypo->GetSourceVertex(2) ); + if ( edge.IsNull() || + !TAssocTool::IsSubShape( edge, srcMesh ) || + !TAssocTool::IsSubShape( edge, _sourceHypo->GetSourceFace() )) + { + SCRUTE((edge.IsNull())); + SCRUTE((TAssocTool::IsSubShape( edge, srcMesh ))); + SCRUTE((TAssocTool::IsSubShape( edge, _sourceHypo->GetSourceFace() ))); + theStatus = HYP_BAD_PARAMETER; + } + else + { + // target vertices + edge = TAssocTool::GetEdgeByVertices + ( tgtMesh, _sourceHypo->GetTargetVertex(1), _sourceHypo->GetTargetVertex(2) ); + if ( edge.IsNull() || + !TAssocTool::IsSubShape( edge, tgtMesh ) || + !TAssocTool::IsSubShape( edge, theShape )) + { + SCRUTE((edge.IsNull())); + SCRUTE((TAssocTool::IsSubShape( edge, tgtMesh ))); + SCRUTE((TAssocTool::IsSubShape( edge, theShape ))); + theStatus = HYP_BAD_PARAMETER; + } + } + } + // check a source face + if ( !TAssocTool::IsSubShape( _sourceHypo->GetSourceFace(), srcMesh )) { + MESSAGE("Bad source face"); + theStatus = HYP_BAD_PARAMETER; + } + } + else + { + theStatus = HYP_INCOMPATIBLE; + } + return ( theStatus == HYP_OK ); +} + +namespace { + + + //================================================================================ + /*! + * \brief define if a node is new or old + * \param node - node to check + * \retval bool - true if the node existed before Compute() is called + */ + //================================================================================ + + bool isOldNode( const SMDS_MeshNode* node ) + { + // old nodes are shared by edges and new ones are shared + // only by faces created by mapper + bool isOld = false; + SMDS_ElemIteratorPtr invElem = node->GetInverseElementIterator(); + while ( !isOld && invElem->more() ) + isOld = ( invElem->next()->GetType() == SMDSAbs_Edge ); + return isOld; + } + + //================================================================================ + /*! + * \brief Class to remove mesh built by pattern mapper on edges + * and vertices in the case of failure of projection algo. + * It does it's job at destruction + */ + //================================================================================ + + class MeshCleaner { + SMESH_subMesh* sm; + public: + MeshCleaner( SMESH_subMesh* faceSubMesh ): sm(faceSubMesh) {} + ~MeshCleaner() { Clean(sm); } + void Release() { sm = 0; } // mesh will not be removed + static void Clean( SMESH_subMesh* sm ) + { + if ( !sm ) return; + switch ( sm->GetSubShape().ShapeType() ) { + case TopAbs_VERTEX: + case TopAbs_EDGE: { + SMDS_NodeIteratorPtr nIt = sm->GetSubMeshDS()->GetNodes(); + SMESHDS_Mesh* mesh = sm->GetFather()->GetMeshDS(); + while ( nIt->more() ) { + const SMDS_MeshNode* node = nIt->next(); + if ( !isOldNode( node ) ) + mesh->RemoveNode( node ); + } + // do not break but iterate over DependsOn() + } + default: + const map< int, SMESH_subMesh * >& subSM = sm->DependsOn(); + map< int, SMESH_subMesh * >::const_iterator i_sm = subSM.begin(); + for ( ; i_sm != subSM.end(); ++i_sm ) + Clean( i_sm->second ); + } + } + }; + + //================================================================================ + /*! + * \brief find new nodes belonging to one free border of mesh on face + * \param sm - submesh on edge or vertex containg nodes to choose from + * \param face - the face bound the submesh + * \param u2nodes - map to fill with nodes + * \param seamNodes - set of found nodes + * \retval bool - is a success + */ + //================================================================================ + + bool getBoundaryNodes ( SMESH_subMesh* sm, + const TopoDS_Face& face, + map< double, const SMDS_MeshNode* > & u2nodes, + set< const SMDS_MeshNode* > & seamNodes) + { + u2nodes.clear(); + seamNodes.clear(); + if ( !sm || !sm->GetSubMeshDS() ) + RETURN_BAD_RESULT("Null submesh"); + + SMDS_NodeIteratorPtr nIt = sm->GetSubMeshDS()->GetNodes(); + switch ( sm->GetSubShape().ShapeType() ) { + + case TopAbs_VERTEX: { + while ( nIt->more() ) { + const SMDS_MeshNode* node = nIt->next(); + if ( isOldNode( node ) ) continue; + u2nodes.insert( make_pair( 0., node )); + seamNodes.insert( node ); + return true; + } + break; + } + case TopAbs_EDGE: { + + // Get submeshes of sub-vertices + const map< int, SMESH_subMesh * >& subSM = sm->DependsOn(); + if ( subSM.size() != 2 ) + RETURN_BAD_RESULT("there must be 2 submeshes of sub-vertices" + " but we have " << subSM.size()); + SMESH_subMesh* smV1 = subSM.begin()->second; + SMESH_subMesh* smV2 = subSM.rbegin()->second; + if ( !smV1->IsMeshComputed() || !smV2->IsMeshComputed() ) + RETURN_BAD_RESULT("Empty vertex submeshes"); + + // Look for a new node on V1 + nIt = smV1->GetSubMeshDS()->GetNodes(); + const SMDS_MeshNode* nV1 = 0; + while ( nIt->more() && !nV1 ) { + const SMDS_MeshNode* node = nIt->next(); + if ( !isOldNode( node ) ) nV1 = node; + } + if ( !nV1 ) + RETURN_BAD_RESULT("No new node found on V1"); + + // Find a new node connected to nV1 and belonging to edge submesh; + const SMDS_MeshNode* nE = 0; + SMESHDS_SubMesh* smDS = sm->GetSubMeshDS(); + SMDS_ElemIteratorPtr vElems = nV1->GetInverseElementIterator(); + while ( vElems->more() && !nE ) { + const SMDS_MeshElement* elem = vElems->next(); + if ( elem->GetType() != SMDSAbs_Face ) + continue; // new nodes are shared by faces + int nbNodes = elem->NbNodes(); + if ( elem->IsQuadratic() ) + nbNodes /= 2; + int iV1 = elem->GetNodeIndex( nV1 ); + // try next aftre nV1 + int iE = SMESH_MesherHelper::WrapIndex( iV1 + 1, nbNodes ); + if ( smDS->Contains( elem->GetNode( iE ) )) + nE = elem->GetNode( iE ); + if ( !nE ) { + // try node before nV1 + iE = SMESH_MesherHelper::WrapIndex( iV1 - 1, nbNodes ); + if ( smDS->Contains( elem->GetNode( iE ))) + nE = elem->GetNode( iE ); + } + if ( nE && elem->IsQuadratic() ) { // find medium node between nV1 and nE + if ( Abs( iV1 - iE ) == 1 ) + nE = elem->GetNode( Min ( iV1, iE ) + nbNodes ); + else + nE = elem->GetNode( elem->NbNodes() - 1 ); + } + } + if ( !nE ) + RETURN_BAD_RESULT("new node on edge not found"); + + // Get the whole free border of a face + list< const SMDS_MeshNode* > bordNodes; + list< const SMDS_MeshElement* > bordFaces; + if ( !SMESH_MeshEditor::FindFreeBorder (nV1, nE, nV1, bordNodes, bordFaces )) + RETURN_BAD_RESULT("free border of a face not found by nodes " << + nV1->GetID() << " " << nE->GetID() ); + + // Insert nodes of the free border to the map until node on V2 encountered + SMESHDS_SubMesh* v2smDS = smV2->GetSubMeshDS(); + list< const SMDS_MeshNode* >::iterator bordIt = bordNodes.begin(); + bordIt++; // skip nV1 + for ( ; bordIt != bordNodes.end(); ++bordIt ) { + const SMDS_MeshNode* node = *bordIt; + if ( v2smDS->Contains( node )) + break; + if ( node->GetPosition()->GetTypeOfPosition() != SMDS_TOP_EDGE ) + RETURN_BAD_RESULT("Bad node position type: node " << node->GetID() << + " pos type " << node->GetPosition()->GetTypeOfPosition()); + const SMDS_EdgePosition* pos = + static_cast(node->GetPosition().get()); + u2nodes.insert( make_pair( pos->GetUParameter(), node )); + seamNodes.insert( node ); + } + if ( u2nodes.size() != seamNodes.size() ) + RETURN_BAD_RESULT("Bad node params on edge " << sm->GetId() << + ", " << u2nodes.size() << " != " << seamNodes.size() ); + return true; + } + default:; + } + RETURN_BAD_RESULT ("Unexpected submesh type"); + + } // bool getBoundaryNodes() + +} // namespace + +//======================================================================= +//function : Compute +//purpose : +//======================================================================= + +bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theShape) +{ + if ( !_sourceHypo ) + return false; + + TopoDS_Face tgtFace = TopoDS::Face( theShape.Oriented(TopAbs_FORWARD)); + TopoDS_Face srcFace = TopoDS::Face( _sourceHypo->GetSourceFace().Oriented(TopAbs_FORWARD)); + + SMESH_Mesh * srcMesh = _sourceHypo->GetSourceMesh(); + SMESH_Mesh * tgtMesh = & theMesh; + if ( !srcMesh ) + srcMesh = tgtMesh; + + SMESHDS_Mesh * meshDS = theMesh.GetMeshDS(); + + SMESH_MesherHelper helper( theMesh ); + helper.SetSubShape( tgtFace ); + + // --------------------------- + // Make subshapes association + // --------------------------- + + TAssocTool::TShapeShapeMap shape2ShapeMap; + TAssocTool::InitVertexAssociation( _sourceHypo, shape2ShapeMap ); + if ( !TAssocTool::FindSubShapeAssociation( tgtFace, tgtMesh, srcFace, srcMesh, + shape2ShapeMap) ) + RETURN_BAD_RESULT("FindSubShapeAssociation failed"); + + // ---------------------------------------------- + // Assure that mesh on a source Face is computed + // ---------------------------------------------- + + SMESH_subMesh* srcSubMesh = srcMesh->GetSubMesh( srcFace ); + SMESH_subMesh* tgtSubMesh = tgtMesh->GetSubMesh( tgtFace ); + + if ( tgtMesh == srcMesh ) { + if ( !TAssocTool::MakeComputed( srcSubMesh )) + RETURN_BAD_RESULT("Impossible to compute the source mesh"); + } + else { + if ( !srcSubMesh->IsMeshComputed() ) + RETURN_BAD_RESULT("Source mesh is not computed"); + } + + // -------------------- + // Prepare to mapping + // -------------------- + + // Load pattern from the source face + SMESH_Pattern mapper; + mapper.Load( srcMesh, srcFace ); + if ( mapper.GetErrorCode() != SMESH_Pattern::ERR_OK ) + RETURN_BAD_RESULT("SMESH_Pattern::Load() failed"); + + // Find the first target vertex corresponding to first vertex of the + // and flag needed to call mapper.Apply() + + TopoDS_Vertex srcV1 = TopoDS::Vertex( mapper.GetSubShape( 1 )); + if ( srcV1.IsNull() ) + RETURN_BAD_RESULT("Mesh is not bound to the face"); + if ( !shape2ShapeMap.IsBound( srcV1 )) + RETURN_BAD_RESULT("Not associated vertices, srcV1 " << srcV1.TShape().operator->() ); + TopoDS_Vertex tgtV1 = TopoDS::Vertex( shape2ShapeMap( srcV1 )); + + if ( !TAssocTool::IsSubShape( srcV1, srcFace )) + RETURN_BAD_RESULT("Wrong srcV1 " << srcV1.TShape().operator->()); + if ( !TAssocTool::IsSubShape( tgtV1, tgtFace )) + RETURN_BAD_RESULT("Wrong tgtV1 " << tgtV1.TShape().operator->()); + + // try to find out orientation by order of edges + bool reverse = false; + list< TopoDS_Edge > tgtEdges, srcEdges; + list< int > nbEdgesInWires; + SMESH_Block::GetOrderedEdges( tgtFace, tgtV1, tgtEdges, nbEdgesInWires); + SMESH_Block::GetOrderedEdges( srcFace, srcV1, srcEdges, nbEdgesInWires); + if ( nbEdgesInWires.front() > 1 ) // possible to find out + { + TopoDS_Edge srcE1 = srcEdges.front(), tgtE1 = tgtEdges.front(); + reverse = ( ! srcE1.IsSame( shape2ShapeMap( tgtE1 ))); + if ( BRep_Tool::IsClosed( tgtE1, tgtFace )) { + reverse = ( srcE1.Orientation() == tgtE1.Orientation() ); + if ( _sourceHypo->GetSourceFace().Orientation() != theShape.Orientation() ) + reverse = !reverse; + } + } + else if ( nbEdgesInWires.front() == 1 ) + { + // TODO::Compare orientation of curves in a sole edge + //RETURN_BAD_RESULT("Not implemented case"); + } + else + { + RETURN_BAD_RESULT("Bad result from SMESH_Block::GetOrderedEdges()"); + } + + // -------------------- + // Perform 2D mapping + // -------------------- + + // Compute mesh on a target face + + mapper.Apply( tgtFace, tgtV1, reverse ); + if ( mapper.GetErrorCode() != SMESH_Pattern::ERR_OK ) + RETURN_BAD_RESULT("SMESH_Pattern::Apply() failed"); + + // Create the mesh + + const bool toCreatePolygons = false, toCreatePolyedrs = false; + mapper.MakeMesh( tgtMesh, toCreatePolygons, toCreatePolyedrs ); + if ( mapper.GetErrorCode() != SMESH_Pattern::ERR_OK ) + RETURN_BAD_RESULT("SMESH_Pattern::MakeMesh() failed"); + + // it will remove mesh built by pattern mapper on edges and vertices + // in failure case + MeshCleaner cleaner( tgtSubMesh ); + + // ------------------------------------------------------------------------- + // mapper doesn't take care of nodes already existing on edges and vertices, + // so we must merge nodes created by it with existing ones + // ------------------------------------------------------------------------- + + SMESH_MeshEditor editor( tgtMesh ); + SMESH_MeshEditor::TListOfListOfNodes groupsOfNodes; + + // Make groups of nodes to merge + + // loop on edge and vertex submeshes of a target face + const map< int, SMESH_subMesh * >& subSM = tgtSubMesh->DependsOn(); + map< int, SMESH_subMesh * >::const_iterator i_subSM = subSM.begin(); + for ( ; i_subSM != subSM.end(); ++i_subSM ) + { + SMESH_subMesh* sm = i_subSM->second; + SMESHDS_SubMesh* smDS = sm->GetSubMeshDS(); + + // Sort new and old nodes of a submesh separately + + bool isSeam = helper.IsSeamShape( sm->GetId() ); + + enum { NEW_NODES, OLD_NODES }; + map< double, const SMDS_MeshNode* > u2nodesMaps[2], u2nodesOnSeam; + map< double, const SMDS_MeshNode* >::iterator u_oldNode, u_newNode, u_newOnSeam, newEnd; + set< const SMDS_MeshNode* > seamNodes; + + // mapper puts on a seam edge nodes from 2 edges + if ( isSeam && ! getBoundaryNodes ( sm, tgtFace, u2nodesOnSeam, seamNodes )) + RETURN_BAD_RESULT("getBoundaryNodes() failed"); + + SMDS_NodeIteratorPtr nIt = smDS->GetNodes(); + while ( nIt->more() ) + { + const SMDS_MeshNode* node = nIt->next(); + bool isOld = isOldNode( node ); + + if ( !isOld && isSeam ) { // new node on a seam edge + if ( seamNodes.find( node ) != seamNodes.end()) + continue; // node is already in the map + } + + // sort nodes on edges by its position + map< double, const SMDS_MeshNode* > & pos2nodes = u2nodesMaps[ isOld ]; + switch ( node->GetPosition()->GetTypeOfPosition() ) + { + case SMDS_TOP_VERTEX: { + pos2nodes.insert( make_pair( 0, node )); + break; + } + case SMDS_TOP_EDGE: { + const SMDS_EdgePosition* pos = + static_cast(node->GetPosition().get()); + pos2nodes.insert( make_pair( pos->GetUParameter(), node )); + break; + } + default: + RETURN_BAD_RESULT("Wrong node position type: "<< + node->GetPosition()->GetTypeOfPosition()); + } + } + if ( u2nodesMaps[ OLD_NODES ].size() != u2nodesMaps[ NEW_NODES ].size() ) + RETURN_BAD_RESULT("Different nb of old and new nodes " << + u2nodesMaps[ OLD_NODES ].size() << " != " << + u2nodesMaps[ NEW_NODES ].size()); + if ( isSeam && u2nodesMaps[ OLD_NODES ].size() != u2nodesOnSeam.size() ) + RETURN_BAD_RESULT("Different nb of old and seam nodes " << + u2nodesMaps[ OLD_NODES ].size() << " != " << u2nodesOnSeam.size()); + + // Make groups of nodes to merge + u_oldNode = u2nodesMaps[ OLD_NODES ].begin(); + u_newNode = u2nodesMaps[ NEW_NODES ].begin(); + newEnd = u2nodesMaps[ NEW_NODES ].end(); + u_newOnSeam = u2nodesOnSeam.begin(); + for ( ; u_newNode != newEnd; ++u_newNode, ++u_oldNode ) { + groupsOfNodes.push_back( list< const SMDS_MeshNode* >() ); + groupsOfNodes.back().push_back( u_oldNode->second ); + groupsOfNodes.back().push_back( u_newNode->second ); + if ( isSeam ) + groupsOfNodes.back().push_back( (u_newOnSeam++)->second ); + } + } + + // Merge + + editor.MergeNodes( groupsOfNodes ); + + // --------------------------- + // Check elements orientation + // --------------------------- + + TopoDS_Face face = tgtFace; + if ( !theMesh.IsMainShape( tgtFace )) + { + // find the main shape + TopoDS_Shape mainShape = meshDS->ShapeToMesh(); + switch ( mainShape.ShapeType() ) { + case TopAbs_SHELL: + case TopAbs_SOLID: break; + default: + TopTools_ListIteratorOfListOfShape ancestIt = theMesh.GetAncestors( face ); + for ( ; ancestIt.More(); ancestIt.Next() ) { + TopAbs_ShapeEnum type = ancestIt.Value().ShapeType(); + if ( type == TopAbs_SOLID ) { + mainShape = ancestIt.Value(); + break; + } else if ( type == TopAbs_SHELL ) { + mainShape = ancestIt.Value(); + } + } + } + // find tgtFace in the main solid or shell to know it's true orientation. + TopExp_Explorer exp( mainShape, TopAbs_FACE ); + for ( ; exp.More(); exp.Next() ) { + if ( tgtFace.IsSame( exp.Current() )) { + face = TopoDS::Face( exp.Current() ); + break; + } + } + } + // Fix orientation + if ( SMESH_Algo::IsReversedSubMesh( face, meshDS )) + { + SMDS_ElemIteratorPtr eIt = meshDS->MeshElements( face )->GetElements(); + while ( eIt->more() ) { + const SMDS_MeshElement* e = eIt->next(); + if ( e->GetType() == SMDSAbs_Face && !editor.Reorient( e )) + RETURN_BAD_RESULT("Pb of SMESH_MeshEditor::Reorient()"); + } + } + + cleaner.Release(); // do not remove mesh + + return true; +} + +//============================================================================= +/*! + * \brief Sets a default event listener to submesh of the source face + * \param subMesh - submesh where algo is set + * + * This method is called when a submesh gets HYP_OK algo_state. + * After being set, event listener is notified on each event of a submesh. + * Arranges that CLEAN event is translated from source submesh to + * the submesh + */ +//============================================================================= + +void StdMeshers_Projection_2D::SetEventListener(SMESH_subMesh* subMesh) +{ + if ( _sourceHypo && ! _sourceHypo->GetSourceFace().IsNull() ) + { + SMESH_Mesh* srcMesh = _sourceHypo->GetSourceMesh(); + if ( !srcMesh ) + srcMesh = subMesh->GetFather(); + + SMESH_subMesh* srcFaceSM = + srcMesh->GetSubMesh( _sourceHypo->GetSourceFace() ); + + subMesh->SetEventListener( new SMESH_subMeshEventListener(), + SMESH_subMeshEventListenerData::MakeData( subMesh ), + srcFaceSM ); + } +} diff --git a/src/StdMeshers/StdMeshers_Projection_2D.hxx b/src/StdMeshers/StdMeshers_Projection_2D.hxx new file mode 100644 index 000000000..efa1c6ebc --- /dev/null +++ b/src/StdMeshers/StdMeshers_Projection_2D.hxx @@ -0,0 +1,63 @@ +// SMESH SMESH : implementaion of SMESH idl descriptions +// +// Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// +// +// File : StdMeshers_Projection_2D.hxx +// Module : SMESH + +#ifndef _SMESH_Projection_2D_HXX_ +#define _SMESH_Projection_2D_HXX_ + +#include "SMESH_2D_Algo.hxx" + +class StdMeshers_ProjectionSource2D; + +class StdMeshers_Projection_2D: public SMESH_2D_Algo +{ +public: + StdMeshers_Projection_2D(int hypId, int studyId, SMESH_Gen* gen); + virtual ~StdMeshers_Projection_2D(); + + virtual bool CheckHypothesis(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + SMESH_Hypothesis::Hypothesis_Status& aStatus); + + virtual bool Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape); + + /*! + * \brief Sets a default event listener to submesh of the source face + * \param whenSetToSubMesh - submesh where algo is set + * + * After being set, event listener is notified on each event of a submesh. + * This method is called when a submesh gets HYP_OK algo_state. + * Arranges that CLEAN event is translated from source submesh to + * the whenSetToSubMesh submesh. + */ + virtual void SetEventListener(SMESH_subMesh* whenSetToSubMesh); + +protected: + + const StdMeshers_ProjectionSource2D* _sourceHypo; + +}; + +#endif diff --git a/src/StdMeshers/StdMeshers_Projection_3D.cxx b/src/StdMeshers/StdMeshers_Projection_3D.cxx new file mode 100644 index 000000000..44b4395f4 --- /dev/null +++ b/src/StdMeshers/StdMeshers_Projection_3D.cxx @@ -0,0 +1,438 @@ +// SMESH SMESH : implementaion of SMESH idl descriptions +// +// Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// +// +// File : StdMeshers_Projection_3D.cxx +// Module : SMESH +// Created : Fri Oct 20 11:37:07 2006 +// Author : Edward AGAPOV (eap) + + +#include "StdMeshers_Projection_3D.hxx" +#include "StdMeshers_ProjectionSource3D.hxx" + +#include "StdMeshers_ProjectionUtils.hxx" + +#include "SMESHDS_Hypothesis.hxx" +#include "SMESHDS_SubMesh.hxx" +#include "SMESH_Block.hxx" +#include "SMESH_Gen.hxx" +#include "SMESH_Mesh.hxx" +#include "SMESH_MeshEditor.hxx" +#include "SMESH_Pattern.hxx" +#include "SMESH_subMesh.hxx" +#include "SMESH_subMeshEventListener.hxx" +#include "SMESH_MesherHelper.hxx" +#include "SMDS_VolumeTool.hxx" +#include "SMDS_PolyhedralVolumeOfNodes.hxx" + +#include "utilities.h" + +#define RETURN_BAD_RESULT(msg) { MESSAGE(msg); return false; } +#define gpXYZ(n) gp_XYZ(n->X(),n->Y(),n->Z()) +#define SHOWYXZ(msg, xyz) // {\ +// gp_Pnt p (xyz); \ +// cout << msg << " ("<< p.X() << "; " <::const_iterator itl; + + const list &hyps = GetUsedHypothesis(aMesh, aShape); + if ( hyps.size() == 0 ) + { + aStatus = SMESH_Hypothesis::HYP_MISSING; + return false; // can't work with no hypothesis + } + + if ( hyps.size() > 1 ) + { + aStatus = SMESH_Hypothesis::HYP_ALREADY_EXIST; + return false; + } + + const SMESHDS_Hypothesis *theHyp = hyps.front(); + + string hypName = theHyp->GetName(); + + aStatus = SMESH_Hypothesis::HYP_OK; + + if (hypName == "ProjectionSource3D") + { + _sourceHypo = static_cast(theHyp); + // Check hypo parameters + + SMESH_Mesh* srcMesh = _sourceHypo->GetSourceMesh(); + SMESH_Mesh* tgtMesh = & aMesh; + if ( !srcMesh ) + srcMesh = tgtMesh; + + // check vertices + if ( _sourceHypo->HasVertexAssociation() ) + { + // source vertices + TopoDS_Shape edge = TAssocTool::GetEdgeByVertices + ( srcMesh, _sourceHypo->GetSourceVertex(1), _sourceHypo->GetSourceVertex(2) ); + if ( edge.IsNull() || + !TAssocTool::IsSubShape( edge, srcMesh ) || + !TAssocTool::IsSubShape( edge, _sourceHypo->GetSource3DShape() )) + { + SCRUTE((edge.IsNull())); + SCRUTE((TAssocTool::IsSubShape( edge, srcMesh ))); + SCRUTE((TAssocTool::IsSubShape( edge, _sourceHypo->GetSource3DShape() ))); + aStatus = SMESH_Hypothesis::HYP_BAD_PARAMETER; + } + else + { + // target vertices + edge = TAssocTool::GetEdgeByVertices + ( tgtMesh, _sourceHypo->GetTargetVertex(1), _sourceHypo->GetTargetVertex(2) ); + if ( edge.IsNull() || + !TAssocTool::IsSubShape( edge, tgtMesh ) || + !TAssocTool::IsSubShape( edge, aShape )) + { + SCRUTE((edge.IsNull())); + SCRUTE((TAssocTool::IsSubShape( edge, tgtMesh ))); + SCRUTE((TAssocTool::IsSubShape( edge, aShape ))); + aStatus = SMESH_Hypothesis::HYP_BAD_PARAMETER; + } + } + } + // check a source shape + if ( !TAssocTool::IsSubShape( _sourceHypo->GetSource3DShape(), srcMesh ) || + ( srcMesh == tgtMesh && aShape == _sourceHypo->GetSource3DShape())) + { + SCRUTE((TAssocTool::IsSubShape( _sourceHypo->GetSource3DShape(), srcMesh))); + SCRUTE((srcMesh == tgtMesh)); + SCRUTE((aShape == _sourceHypo->GetSource3DShape())); + aStatus = SMESH_Hypothesis::HYP_BAD_PARAMETER; + } + } + else + { + aStatus = SMESH_Hypothesis::HYP_INCOMPATIBLE; + } + return ( aStatus == HYP_OK ); +} + +//======================================================================= +//function : Compute +//purpose : +//======================================================================= + +bool StdMeshers_Projection_3D::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape) +{ + if ( !_sourceHypo ) + return false; + + SMESH_Mesh * srcMesh = _sourceHypo->GetSourceMesh(); + SMESH_Mesh * tgtMesh = & aMesh; + if ( !srcMesh ) + srcMesh = tgtMesh; + + SMESHDS_Mesh * srcMeshDS = srcMesh->GetMeshDS(); + SMESHDS_Mesh * tgtMeshDS = tgtMesh->GetMeshDS(); + + // get shell from shape3D + TopoDS_Shell srcShell, tgtShell; + TopExp_Explorer exp( _sourceHypo->GetSource3DShape(), TopAbs_SHELL ); + int nbShell; + for ( nbShell = 0; exp.More(); exp.Next(), ++nbShell ) + srcShell = TopoDS::Shell( exp.Current() ); + if ( nbShell != 1 ) + RETURN_BAD_RESULT("There must be 1 shell in the source shape"); + + exp.Init( aShape, TopAbs_SHELL ); + for ( nbShell = 0; exp.More(); exp.Next(), ++nbShell ) + tgtShell = TopoDS::Shell( exp.Current() ); + if ( nbShell != 1 ) + RETURN_BAD_RESULT("There must be 1 shell in the target shape"); + + // Assure that mesh on a source shape is computed + + SMESH_subMesh* srcSubMesh = srcMesh->GetSubMesh( _sourceHypo->GetSource3DShape() ); + //SMESH_subMesh* tgtSubMesh = tgtMesh->GetSubMesh( aShape ); + + if ( tgtMesh == srcMesh && !aShape.IsSame( _sourceHypo->GetSource3DShape() )) { + if ( !TAssocTool::MakeComputed( srcSubMesh )) + RETURN_BAD_RESULT("Impossible to compute the source mesh"); + } + else { + if ( !srcSubMesh->IsMeshComputed() ) + RETURN_BAD_RESULT("Source mesh is not computed"); + } + + // Find 2 pairs of corresponding vertices + + TopoDS_Vertex tgtV000, tgtV100, srcV000, srcV100; + TAssocTool::TShapeShapeMap shape2ShapeMap; + + if ( _sourceHypo->HasVertexAssociation() ) + { + tgtV000 = _sourceHypo->GetTargetVertex(1); + tgtV100 = _sourceHypo->GetTargetVertex(2); + srcV000 = _sourceHypo->GetSourceVertex(1); + srcV100 = _sourceHypo->GetSourceVertex(2); + } + else + { + if ( !TAssocTool::FindSubShapeAssociation( tgtShell, tgtMesh, srcShell, srcMesh, + shape2ShapeMap) ) + RETURN_BAD_RESULT("FindSubShapeAssociation() failed"); + + exp.Init( tgtShell, TopAbs_EDGE ); + TopExp::Vertices( TopoDS::Edge( exp.Current() ), tgtV000, tgtV100 ); + + if ( !shape2ShapeMap.IsBound( tgtV000 ) || !shape2ShapeMap.IsBound( tgtV100 )) + RETURN_BAD_RESULT("Shape associating not done"); + srcV000 = TopoDS::Vertex( shape2ShapeMap( tgtV000 )); + srcV100 = TopoDS::Vertex( shape2ShapeMap( tgtV100 )); + if ( !TAssocTool::IsSubShape( srcV000, srcShell ) || + !TAssocTool::IsSubShape( srcV100, srcShell )) + RETURN_BAD_RESULT("Wrong target vertices"); + } + + // Load 2 SMESH_Block's with src and tgt shells + + SMESH_Block srcBlock, tgtBlock; + TopTools_IndexedMapOfOrientedShape scrShapes, tgtShapes; + if ( !tgtBlock.LoadBlockShapes( tgtShell, tgtV000, tgtV100, tgtShapes )) + RETURN_BAD_RESULT("SMESH_Block::LoadBlockShapes(tgtShell) failed"); + + if ( !srcBlock.LoadBlockShapes( srcShell, srcV000, srcV100, scrShapes )) + RETURN_BAD_RESULT("SMESH_Block::LoadBlockShapes(srcShell) failed"); + + // Find matching nodes of src and tgt shells + + TNodeNodeMap src2tgtNodeMap; + for ( int fId = SMESH_Block::ID_FirstF; fId < SMESH_Block::ID_Shell; ++fId ) + { + // Corresponding subshapes + TopoDS_Face srcFace = TopoDS::Face( scrShapes( fId )); + TopoDS_Face tgtFace = TopoDS::Face( tgtShapes( fId )); + if ( _sourceHypo->HasVertexAssociation() ) { // associate face subshapes + shape2ShapeMap.Clear(); + vector< int > edgeIdVec; + SMESH_Block::GetFaceEdgesIDs( fId, edgeIdVec ); + for ( int i = 0; i < edgeIdVec.size(); ++i ) { + int eID = edgeIdVec[ i ]; + shape2ShapeMap.Bind( tgtShapes( eID ), scrShapes( eID )); + if ( i < 2 ) { + vector< int > vertexIdVec; + SMESH_Block::GetEdgeVertexIDs( eID, vertexIdVec ); + shape2ShapeMap.Bind( tgtShapes( vertexIdVec[0] ), scrShapes( vertexIdVec[0] )); + shape2ShapeMap.Bind( tgtShapes( vertexIdVec[1] ), scrShapes( vertexIdVec[1] )); + } + } + } + // Find matching nodes of tgt and src faces + TNodeNodeMap faceMatchingNodes; + if ( ! TAssocTool::FindMatchingNodesOnFaces( srcFace, srcMesh, tgtFace, tgtMesh, + shape2ShapeMap, faceMatchingNodes )) + RETURN_BAD_RESULT("Different mesh on corresponding src and tgt faces: " + << srcMeshDS->ShapeToIndex( srcFace ) << " and " + << tgtMeshDS->ShapeToIndex( tgtFace )); + + // put found matching nodes of 2 faces to the global map + src2tgtNodeMap.insert( faceMatchingNodes.begin(), faceMatchingNodes.end() ); + } + + // ------------------ + // Make mesh + // ------------------ + + SMDS_VolumeTool volTool; + SMESH_MesherHelper helper( *tgtMesh ); + helper.IsQuadraticSubMesh( aShape ); + + SMESHDS_SubMesh* srcSMDS = srcSubMesh->GetSubMeshDS(); + SMDS_ElemIteratorPtr volIt = srcSMDS->GetElements(); + while ( volIt->more() ) // loop on source volumes + { + const SMDS_MeshElement* srcVol = volIt->next(); + if ( !srcVol || srcVol->GetType() != SMDSAbs_Volume ) + continue; + int nbNodes = srcVol->NbNodes(); + SMDS_VolumeTool::VolumeType volType = volTool.GetType( nbNodes ); + if ( srcVol->IsQuadratic() ) + nbNodes = volTool.NbCornerNodes( volType ); + + // Find or create a new tgt node for each node of a src volume + + vector< const SMDS_MeshNode* > nodes( nbNodes ); + for ( int i = 0; i < nbNodes; ++i ) + { + const SMDS_MeshNode* srcNode = srcVol->GetNode( i ); + const SMDS_MeshNode* tgtNode = 0; + TNodeNodeMap::iterator sN_tN = src2tgtNodeMap.find( srcNode ); + if ( sN_tN != src2tgtNodeMap.end() ) // found + { + tgtNode = sN_tN->second; + } + else // Create a new tgt node + { + // compute normalized parameters of source node in srcBlock + gp_Pnt srcCoord = gpXYZ( srcNode ); + gp_XYZ srcParam; + if ( !srcBlock.ComputeParameters( srcCoord, srcParam )) + RETURN_BAD_RESULT("srcBlock.ComputeParameters() failed"); + // compute coordinates of target node by srcParam + gp_XYZ tgtXYZ; + if ( !tgtBlock.ShellPoint( srcParam, tgtXYZ )) + RETURN_BAD_RESULT("tgtBlock.ShellPoint() failed"); + // add node + SMDS_MeshNode* newNode = tgtMeshDS->AddNode( tgtXYZ.X(), tgtXYZ.Y(), tgtXYZ.Z() ); + tgtMeshDS->SetNodeInVolume( newNode, helper.GetSubShapeID() ); + tgtNode = newNode; + src2tgtNodeMap.insert( make_pair( srcNode, tgtNode )); + } + nodes[ i ] = tgtNode; + } + + // Create a new volume + + SMDS_MeshVolume * tgtVol = 0; + switch ( volType ) { + case SMDS_VolumeTool::TETRA : + case SMDS_VolumeTool::QUAD_TETRA: + tgtVol = helper.AddVolume( nodes[0], + nodes[1], + nodes[2], + nodes[3]); break; + case SMDS_VolumeTool::PYRAM : + case SMDS_VolumeTool::QUAD_PYRAM: + tgtVol = helper.AddVolume( nodes[0], + nodes[1], + nodes[2], + nodes[3], + nodes[4]); break; + case SMDS_VolumeTool::PENTA : + case SMDS_VolumeTool::QUAD_PENTA: + tgtVol = helper.AddVolume( nodes[0], + nodes[1], + nodes[2], + nodes[3], + nodes[4], + nodes[5]); break; + case SMDS_VolumeTool::HEXA : + case SMDS_VolumeTool::QUAD_HEXA : + tgtVol = helper.AddVolume( nodes[0], + nodes[1], + nodes[2], + nodes[3], + nodes[4], + nodes[5], + nodes[6], + nodes[7]); break; + default: // polyhedron + const SMDS_PolyhedralVolumeOfNodes * poly = + dynamic_cast( srcVol ); + if ( !poly ) + RETURN_BAD_RESULT("Unexpected volume type"); + vector quantities( poly->NbFaces(), 0 ); + for ( int i = 0; i < quantities.size(); ++i ) + quantities[ i ] = poly->NbFaceNodes( i + 1 ); + tgtVol = tgtMeshDS->AddPolyhedralVolume( nodes, quantities ); + } + if ( tgtVol ) { + tgtMeshDS->SetMeshElementOnShape( tgtVol, helper.GetSubShapeID() ); + } + } // loop on volumes of src shell + + return true; +} + +//============================================================================= +/*! + * \brief Sets a default event listener to submesh of the source shape + * \param subMesh - submesh where algo is set + * + * This method is called when a submesh gets HYP_OK algo_state. + * After being set, event listener is notified on each event of a submesh. + * Arranges that CLEAN event is translated from source submesh to + * the submesh + */ +//============================================================================= + +void StdMeshers_Projection_3D::SetEventListener(SMESH_subMesh* subMesh) +{ + if ( _sourceHypo && ! _sourceHypo->GetSource3DShape().IsNull() ) + { + SMESH_Mesh* srcMesh = _sourceHypo->GetSourceMesh(); + if ( !srcMesh ) + srcMesh = subMesh->GetFather(); + + SMESH_subMesh* srcShapeSM = + srcMesh->GetSubMesh( _sourceHypo->GetSource3DShape() ); + + if ( srcShapeSM != subMesh ) + subMesh->SetEventListener( new SMESH_subMeshEventListener(), + SMESH_subMeshEventListenerData::MakeData( subMesh ), + srcShapeSM ); + } +} + diff --git a/src/StdMeshers/StdMeshers_Projection_3D.hxx b/src/StdMeshers/StdMeshers_Projection_3D.hxx new file mode 100644 index 000000000..abc50e79d --- /dev/null +++ b/src/StdMeshers/StdMeshers_Projection_3D.hxx @@ -0,0 +1,61 @@ +// SMESH SMESH : implementaion of SMESH idl descriptions +// +// Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// +// +// File : StdMeshers_Projection_3D.hxx +// Module : SMESH + +#ifndef _SMESH_Projection_3D_HXX_ +#define _SMESH_Projection_3D_HXX_ + +#include "SMESH_3D_Algo.hxx" + +class StdMeshers_ProjectionSource3D; + +class StdMeshers_Projection_3D: public SMESH_3D_Algo +{ +public: + StdMeshers_Projection_3D(int hypId, int studyId, SMESH_Gen* gen); + virtual ~StdMeshers_Projection_3D(); + + virtual bool CheckHypothesis(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + SMESH_Hypothesis::Hypothesis_Status& aStatus); + + virtual bool Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape); + + /*! + * \brief Sets a default event listener to submesh of the source shape + * \param whenSetToSubMesh - submesh where algo is set + * + * Arranges that CLEAN event is translated from source submesh to + * the whenSetToSubMesh submesh. + */ + virtual void SetEventListener(SMESH_subMesh* whenSetToSubMesh); + +protected: + + const StdMeshers_ProjectionSource3D* _sourceHypo; + +}; + +#endif diff --git a/src/StdMeshers/StdMeshers_RadialPrism_3D.cxx b/src/StdMeshers/StdMeshers_RadialPrism_3D.cxx new file mode 100644 index 000000000..456400032 --- /dev/null +++ b/src/StdMeshers/StdMeshers_RadialPrism_3D.cxx @@ -0,0 +1,372 @@ +// SMESH SMESH : implementaion of SMESH idl descriptions +// +// Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// +// +// File : StdMeshers_RadialPrism_3D.cxx +// Module : SMESH +// Created : Fri Oct 20 11:37:07 2006 +// Author : Edward AGAPOV (eap) + + +#include "StdMeshers_RadialPrism_3D.hxx" + +#include "StdMeshers_ProjectionUtils.hxx" +#include "StdMeshers_NumberOfLayers.hxx" +#include "StdMeshers_LayerDistribution.hxx" +#include "StdMeshers_Prism_3D.hxx" +#include "StdMeshers_Regular_1D.hxx" + +#include "SMDS_MeshNode.hxx" +#include "SMESHDS_SubMesh.hxx" +#include "SMESH_Gen.hxx" +#include "SMESH_Mesh.hxx" +#include "SMESH_MeshEditor.hxx" +#include "SMESH_MesherHelper.hxx" +#include "SMESH_subMesh.hxx" + +#include "utilities.h" + +#include +#include +#include +#include +#include +#include +#include + + +using namespace std; + +#define RETURN_BAD_RESULT(msg) { MESSAGE(msg); return false; } +#define gpXYZ(n) gp_XYZ(n->X(),n->Y(),n->Z()) + +typedef StdMeshers_ProjectionUtils TAssocTool; + +//======================================================================= +//function : StdMeshers_RadialPrism_3D +//purpose : +//======================================================================= + +StdMeshers_RadialPrism_3D::StdMeshers_RadialPrism_3D(int hypId, int studyId, SMESH_Gen* gen) + :SMESH_3D_Algo(hypId, studyId, gen) +{ + _name = "RadialPrism_3D"; + _shapeType = (1 << TopAbs_SOLID); // 1 bit per shape type + + _compatibleHypothesis.push_back("LayerDistribution"); + _compatibleHypothesis.push_back("NumberOfLayers"); + myNbLayerHypo = 0; + myDistributionHypo = 0; +} + +//================================================================================ +/*! + * \brief Destructor + */ +//================================================================================ + +StdMeshers_RadialPrism_3D::~StdMeshers_RadialPrism_3D() +{} + +//======================================================================= +//function : CheckHypothesis +//purpose : +//======================================================================= + +bool StdMeshers_RadialPrism_3D::CheckHypothesis(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + SMESH_Hypothesis::Hypothesis_Status& aStatus) +{ + // check aShape that must have 2 shells + if ( TAssocTool::Count( aShape, TopAbs_SOLID, 0 ) != 1 || + TAssocTool::Count( aShape, TopAbs_SHELL, 0 ) != 2 ) + { + aStatus = HYP_BAD_GEOMETRY; + return false; + } + + myNbLayerHypo = 0; + myDistributionHypo = 0; + + list ::const_iterator itl; + + const list &hyps = GetUsedHypothesis(aMesh, aShape); + if ( hyps.size() == 0 ) + { + aStatus = SMESH_Hypothesis::HYP_MISSING; + return false; // can't work with no hypothesis + } + + if ( hyps.size() > 1 ) + { + aStatus = SMESH_Hypothesis::HYP_ALREADY_EXIST; + return false; + } + + const SMESHDS_Hypothesis *theHyp = hyps.front(); + + string hypName = theHyp->GetName(); + + if (hypName == "NumberOfLayers") + { + myNbLayerHypo = static_cast(theHyp); + aStatus = SMESH_Hypothesis::HYP_OK; + return true; + } + if (hypName == "LayerDistribution") + { + myDistributionHypo = static_cast(theHyp); + aStatus = SMESH_Hypothesis::HYP_OK; + return true; + } + aStatus = SMESH_Hypothesis::HYP_INCOMPATIBLE; + return true; +} + +//======================================================================= +//function : Compute +//purpose : +//======================================================================= + +bool StdMeshers_RadialPrism_3D::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape) +{ + TopExp_Explorer exp; + SMESHDS_Mesh * meshDS = aMesh.GetMeshDS(); + + myHelper = new SMESH_MesherHelper( aMesh ); + myHelper->IsQuadraticSubMesh( aShape ); + // to delete helper at exit from Compute() + std::auto_ptr helperDeleter( myHelper ); + + // get 2 shells + TopoDS_Solid solid = TopoDS::Solid( aShape ); + TopoDS_Shell outerShell = BRepTools::OuterShell( solid ); + TopoDS_Shape innerShell; + int nbShells = 0; + for ( TopoDS_Iterator It (solid); It.More(); It.Next(), ++nbShells ) + if ( !outerShell.IsSame( It.Value() )) + innerShell = It.Value(); + if ( nbShells != 2 ) + RETURN_BAD_RESULT("Must be 2 shells"); + + // ---------------------------------- + // Associate subshapes of the shells + // ---------------------------------- + + TAssocTool::TShapeShapeMap shape2ShapeMap; + if ( !TAssocTool::FindSubShapeAssociation( outerShell, &aMesh, + innerShell, &aMesh, + shape2ShapeMap) ) + RETURN_BAD_RESULT("FindSubShapeAssociation failed"); + + // ------------------ + // Make mesh + // ------------------ + + TNode2ColumnMap node2columnMap; + myLayerPositions.clear(); + + for ( exp.Init( outerShell, TopAbs_FACE ); exp.More(); exp.Next() ) + { + // Corresponding subshapes + TopoDS_Face outFace = TopoDS::Face( exp.Current() ); + TopoDS_Face inFace; + if ( !shape2ShapeMap.IsBound( outFace )) { + RETURN_BAD_RESULT("Association not found for face " << meshDS->ShapeToIndex( outFace )); + } else { + inFace = TopoDS::Face( shape2ShapeMap( outFace )); + } + + // Find matching nodes of in and out faces + TNodeNodeMap nodeIn2OutMap; + if ( ! TAssocTool::FindMatchingNodesOnFaces( inFace, &aMesh, outFace, &aMesh, + shape2ShapeMap, nodeIn2OutMap )) + RETURN_BAD_RESULT("Different mesh on corresponding out and in faces: " + << meshDS->ShapeToIndex( outFace ) << " and " + << meshDS->ShapeToIndex( inFace )); + // Create volumes + + SMDS_ElemIteratorPtr faceIt = meshDS->MeshElements( inFace )->GetElements(); + while ( faceIt->more() ) // loop on faces on inFace + { + const SMDS_MeshElement* face = faceIt->next(); + if ( !face || face->GetType() != SMDSAbs_Face ) + continue; + int nbNodes = face->NbNodes(); + if ( face->IsQuadratic() ) + nbNodes /= 2; + + // find node columns for each node + vector< const TNodeColumn* > columns( nbNodes ); + for ( int i = 0; i < nbNodes; ++i ) + { + const SMDS_MeshNode* n = face->GetNode( i ); + TNode2ColumnMap::iterator n_col = node2columnMap.find( n ); + if ( n_col != node2columnMap.end() ) + columns[ i ] = & n_col->second; + else + columns[ i ] = makeNodeColumn( node2columnMap, n, nodeIn2OutMap[ n ] ); + } + + StdMeshers_Prism_3D::AddPrisms( columns, myHelper ); + } + } // loop on faces of out shell + + return true; +} + +//================================================================================ +/*! + * \brief Create a column of nodes from outNode to inNode + * \param n2ColMap - map of node columns to add a created column + * \param outNode - botton node of a column + * \param inNode - top node of a column + * \retval const TNodeColumn* - a new column pointer + */ +//================================================================================ + +TNodeColumn* StdMeshers_RadialPrism_3D::makeNodeColumn( TNode2ColumnMap& n2ColMap, + const SMDS_MeshNode* outNode, + const SMDS_MeshNode* inNode) +{ + SMESHDS_Mesh * meshDS = myHelper->GetMeshDS(); + int shapeID = myHelper->GetSubShapeID(); + + if ( myLayerPositions.empty() ) + computeLayerPositions( gpXYZ( inNode ), gpXYZ( outNode )); + + int nbSegments = myLayerPositions.size() + 1; + + TNode2ColumnMap::iterator n_col = + n2ColMap.insert( make_pair( outNode, TNodeColumn() )).first; + TNodeColumn & column = n_col->second; + column.resize( nbSegments + 1 ); + column.front() = outNode; + column.back() = inNode; + + gp_XYZ p1 = gpXYZ( outNode ); + gp_XYZ p2 = gpXYZ( inNode ); + for ( int z = 1; z < nbSegments; ++z ) + { + double r = myLayerPositions[ z - 1 ]; + gp_XYZ p = ( 1 - r ) * p1 + r * p2; + SMDS_MeshNode* n = meshDS->AddNode( p.X(), p.Y(), p.Z() ); + meshDS->SetNodeInVolume( n, shapeID ); + column[ z ] = n; + } + + return & column; +} + +//================================================================================ +//================================================================================ +/*! + * \brief Class computing layers distribution using data of + * StdMeshers_LayerDistribution hypothesis + */ +//================================================================================ +//================================================================================ + +class TNodeDistributor: private StdMeshers_Regular_1D +{ + list myUsedHyps; +public: + // ----------------------------------------------------------------------------- + static TNodeDistributor* GetDistributor(SMESH_Mesh& aMesh) + { + const int myID = -1000; + map < int, SMESH_1D_Algo * > & algoMap = aMesh.GetGen()->_map1D_Algo; + map < int, SMESH_1D_Algo * >::iterator id_algo = algoMap.find( myID ); + if ( id_algo == algoMap.end() ) + return new TNodeDistributor( myID, 0, aMesh.GetGen() ); + return static_cast< TNodeDistributor* >( id_algo->second ); + } + // ----------------------------------------------------------------------------- + bool Compute( vector< double > & positions, + gp_Pnt pIn, + gp_Pnt pOut, + SMESH_Mesh& aMesh, + const StdMeshers_LayerDistribution* hyp) + { + double len = pIn.Distance( pOut ); + if ( len <= DBL_MIN ) RETURN_BAD_RESULT("Bad points"); + + if ( !hyp || !hyp->GetLayerDistribution() ) + RETURN_BAD_RESULT("Bad StdMeshers_LayerDistribution hypothesis"); + myUsedHyps.clear(); + myUsedHyps.push_back( hyp->GetLayerDistribution() ); + + TopoDS_Edge edge = BRepBuilderAPI_MakeEdge( pIn, pOut ); + + SMESH_Hypothesis::Hypothesis_Status aStatus; + if ( !StdMeshers_Regular_1D::CheckHypothesis( aMesh, edge, aStatus )) + RETURN_BAD_RESULT("StdMeshers_Regular_1D::CheckHypothesis() failed with status "< params; + if ( !StdMeshers_Regular_1D::computeInternalParameters( edge, params, false )) + RETURN_BAD_RESULT("StdMeshers_Regular_1D::computeInternalParameters() failed"); + + positions.clear(); + positions.reserve( params.size() ); + for (list::iterator itU = params.begin(); itU != params.end(); itU++) + positions.push_back( *itU / len ); + return true; + } +protected: + // ----------------------------------------------------------------------------- + TNodeDistributor( int hypId, int studyId, SMESH_Gen* gen) + : StdMeshers_Regular_1D( hypId, studyId, gen) + { + } + // ----------------------------------------------------------------------------- + virtual const list & + GetUsedHypothesis(SMESH_Mesh &, const TopoDS_Shape &, const bool) + { + return myUsedHyps; + } + // ----------------------------------------------------------------------------- +}; + +//================================================================================ +/*! + * \brief Compute positions of nodes between the internal and the external surfaces + * \retval bool - is a success + */ +//================================================================================ + +bool StdMeshers_RadialPrism_3D::computeLayerPositions(gp_Pnt pIn, gp_Pnt pOut) +{ + if ( myNbLayerHypo ) + { + int nbSegments = myNbLayerHypo->GetNumberOfLayers(); + myLayerPositions.resize( nbSegments - 1 ); + for ( int z = 1; z < nbSegments; ++z ) + myLayerPositions[ z - 1 ] = double( z )/ double( nbSegments ); + return true; + } + if ( myDistributionHypo ) { + SMESH_Mesh * mesh = myHelper->GetMesh(); + return TNodeDistributor::GetDistributor(*mesh)->Compute( myLayerPositions, pIn, pOut, + *mesh, myDistributionHypo ); + } + RETURN_BAD_RESULT("Bad hypothesis"); +} diff --git a/src/StdMeshers/StdMeshers_RadialPrism_3D.hxx b/src/StdMeshers/StdMeshers_RadialPrism_3D.hxx new file mode 100644 index 000000000..4c604ea32 --- /dev/null +++ b/src/StdMeshers/StdMeshers_RadialPrism_3D.hxx @@ -0,0 +1,70 @@ +// SMESH SMESH : implementaion of SMESH idl descriptions +// +// Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// +// +// File : StdMeshers_RadialPrism_3D.hxx +// Module : SMESH + +#ifndef _SMESH_RadialPrism_3D_HXX_ +#define _SMESH_RadialPrism_3D_HXX_ + +#include "SMESH_3D_Algo.hxx" +#include "SMDS_MeshNode.hxx" + +#include +#include + +class StdMeshers_NumberOfLayers; +class StdMeshers_LayerDistribution; +class SMESH_MesherHelper; + +class StdMeshers_RadialPrism_3D: public SMESH_3D_Algo +{ +public: + StdMeshers_RadialPrism_3D(int hypId, int studyId, SMESH_Gen* gen); + virtual ~StdMeshers_RadialPrism_3D(); + + virtual bool CheckHypothesis(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + SMESH_Hypothesis::Hypothesis_Status& aStatus); + + virtual bool Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape); + +protected: + + typedef vector TNodeColumn; + typedef map< const SMDS_MeshNode*, TNodeColumn > TNode2ColumnMap; + + TNodeColumn* makeNodeColumn( TNode2ColumnMap& n2ColMap, + const SMDS_MeshNode* outNode, + const SMDS_MeshNode* inNode); + + bool computeLayerPositions(gp_Pnt pIn, gp_Pnt pOut); + + + const StdMeshers_NumberOfLayers* myNbLayerHypo; + const StdMeshers_LayerDistribution* myDistributionHypo; + SMESH_MesherHelper* myHelper; + vector< double > myLayerPositions; +}; + +#endif -- 2.39.2