Salome HOME
PAL13330( When mesh generation does not success, trace where )
[modules/smesh.git] / src / StdMeshers / StdMeshers_Projection_1D.cxx
1 //  SMESH SMESH : implementaion of SMESH idl descriptions
2 //
3 //  Copyright (C) 2003  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS 
5 // 
6 //  This library is free software; you can redistribute it and/or 
7 //  modify it under the terms of the GNU Lesser General Public 
8 //  License as published by the Free Software Foundation; either 
9 //  version 2.1 of the License. 
10 // 
11 //  This library is distributed in the hope that it will be useful, 
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of 
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
14 //  Lesser General Public License for more details. 
15 // 
16 //  You should have received a copy of the GNU Lesser General Public 
17 //  License along with this library; if not, write to the Free Software 
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA 
19 // 
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 //
23 //
24 // File      : StdMeshers_Projection_1D.cxx
25 // Module    : SMESH
26 // Created   : Fri Oct 20 11:37:07 2006
27 // Author    : Edward AGAPOV (eap)
28
29
30 #include "StdMeshers_Projection_1D.hxx"
31
32 #include "StdMeshers_ProjectionSource1D.hxx"
33 #include "StdMeshers_ProjectionUtils.hxx"
34
35 #include "SMDS_MeshNode.hxx"
36 #include "SMDS_MeshElement.hxx"
37 #include "SMESHDS_Mesh.hxx"
38 #include "SMESHDS_SubMesh.hxx"
39 #include "SMESH_Mesh.hxx"
40 #include "SMESH_MesherHelper.hxx"
41 #include "SMESH_subMesh.hxx"
42 #include "SMESH_subMeshEventListener.hxx"
43 #include "SMESH_Gen.hxx"
44 #include "SMESH_Comment.hxx"
45
46 #include <BRepAdaptor_Curve.hxx>
47 #include <BRep_Tool.hxx>
48 #include <GCPnts_AbscissaPoint.hxx>
49 #include <TopoDS.hxx>
50 #include <gp_Pnt.hxx>
51
52 #include "utilities.h"
53
54
55 using namespace std;
56
57 #define RETURN_BAD_RESULT(msg) { MESSAGE(msg); return false; }
58
59 typedef StdMeshers_ProjectionUtils TAssocTool;
60
61 //=======================================================================
62 //function : StdMeshers_Projection_1D
63 //purpose  : 
64 //=======================================================================
65
66 StdMeshers_Projection_1D::StdMeshers_Projection_1D(int hypId, int studyId, SMESH_Gen* gen)
67   :SMESH_1D_Algo(hypId, studyId, gen)
68 {
69   _name = "Projection_1D";
70   _shapeType = (1 << TopAbs_EDGE);      // 1 bit per shape type
71
72   _compatibleHypothesis.push_back("ProjectionSource1D");
73   _sourceHypo = 0;
74 }
75
76 //================================================================================
77 /*!
78  * \brief Destructor
79  */
80 //================================================================================
81
82 StdMeshers_Projection_1D::~StdMeshers_Projection_1D()
83 {}
84
85 //=======================================================================
86 //function : CheckHypothesis
87 //purpose  : 
88 //=======================================================================
89
90 bool StdMeshers_Projection_1D::CheckHypothesis(SMESH_Mesh&                          aMesh,
91                                                const TopoDS_Shape&                  aShape,
92                                                SMESH_Hypothesis::Hypothesis_Status& aStatus)
93 {
94   _sourceHypo = 0;
95   list <const SMESHDS_Hypothesis * >::const_iterator itl;
96
97   const list <const SMESHDS_Hypothesis * >&hyps = GetUsedHypothesis(aMesh, aShape);
98   if ( hyps.size() == 0 )
99   {
100     aStatus = SMESH_Hypothesis::HYP_MISSING;
101     return false;  // can't work with no hypothesis
102   }
103
104   if ( hyps.size() > 1 )
105   {
106     aStatus = SMESH_Hypothesis::HYP_ALREADY_EXIST;
107     return false;
108   }
109
110   const SMESHDS_Hypothesis *theHyp = hyps.front();
111
112   string hypName = theHyp->GetName();
113
114   aStatus = SMESH_Hypothesis::HYP_OK;
115
116   if (hypName == "ProjectionSource1D")
117   {
118     _sourceHypo = static_cast<const StdMeshers_ProjectionSource1D *>(theHyp);
119
120     // Check hypo parameters
121
122     SMESH_Mesh* srcMesh = _sourceHypo->GetSourceMesh();
123     SMESH_Mesh* tgtMesh = & aMesh;
124     if ( !srcMesh )
125       srcMesh = tgtMesh;
126
127     // check vertices
128     if ( _sourceHypo->HasVertexAssociation() )
129     {
130       // source and target vertices
131       if ( !TAssocTool::IsSubShape( _sourceHypo->GetSourceVertex(), srcMesh ) ||
132            !TAssocTool::IsSubShape( _sourceHypo->GetTargetVertex(), tgtMesh ) ||
133            !TAssocTool::IsSubShape( _sourceHypo->GetTargetVertex(), aShape )  ||
134            !TAssocTool::IsSubShape( _sourceHypo->GetSourceVertex(),
135                                     _sourceHypo->GetSourceEdge() ))
136       {
137         aStatus = SMESH_Hypothesis::HYP_BAD_PARAMETER;
138         SCRUTE((TAssocTool::IsSubShape( _sourceHypo->GetSourceVertex(), srcMesh )));
139         SCRUTE((TAssocTool::IsSubShape( _sourceHypo->GetTargetVertex(), tgtMesh )));
140         SCRUTE((TAssocTool::IsSubShape( _sourceHypo->GetTargetVertex(), aShape ) ));
141         SCRUTE((TAssocTool::IsSubShape( _sourceHypo->GetSourceVertex(),
142                                         _sourceHypo->GetSourceEdge() )));
143       }
144     }
145     // check source edge
146     if ( !TAssocTool::IsSubShape( _sourceHypo->GetSourceEdge(), srcMesh ) ||
147          ( srcMesh == tgtMesh && aShape == _sourceHypo->GetSourceEdge() ))
148     {
149       aStatus = HYP_BAD_PARAMETER;
150       SCRUTE((TAssocTool::IsSubShape( _sourceHypo->GetSourceEdge(), srcMesh )));
151       SCRUTE((srcMesh == tgtMesh));
152       SCRUTE(( aShape == _sourceHypo->GetSourceEdge() ));
153     }
154   }
155   else
156   {
157     aStatus = SMESH_Hypothesis::HYP_INCOMPATIBLE;
158   }
159   return ( aStatus == HYP_OK );
160 }
161
162 //=======================================================================
163 //function : Compute
164 //purpose  : 
165 //=======================================================================
166
167 bool StdMeshers_Projection_1D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theShape)
168 {
169   if ( !_sourceHypo )
170     return false;
171
172   TopoDS_Edge tgtEdge = TopoDS::Edge( theShape.Oriented(TopAbs_FORWARD));
173   TopoDS_Edge srcEdge = TopoDS::Edge( _sourceHypo->GetSourceEdge().Oriented(TopAbs_FORWARD));
174
175   TopoDS_Vertex tgtV[2], srcV[2];
176   TopExp::Vertices( tgtEdge, tgtV[0], tgtV[1] );
177   TopExp::Vertices( srcEdge, srcV[0], srcV[1] );
178
179   SMESH_Mesh * srcMesh = _sourceHypo->GetSourceMesh(); 
180   SMESH_Mesh * tgtMesh = & theMesh;
181   if ( !srcMesh )
182     srcMesh = tgtMesh;
183
184   SMESHDS_Mesh * meshDS = theMesh.GetMeshDS();
185
186   // ---------------------------
187   // Make subshapes association
188   // ---------------------------
189
190   TAssocTool::TShapeShapeMap shape2ShapeMap;
191   TAssocTool::InitVertexAssociation( _sourceHypo, shape2ShapeMap );
192   if ( !TAssocTool::FindSubShapeAssociation( tgtEdge, tgtMesh, srcEdge, srcMesh,
193                                              shape2ShapeMap) )
194     return error(dfltErr(),SMESH_Comment("Vertices association failed" ));
195
196   // ----------------------------------------------
197   // Assure that mesh on a source edge is computed
198   // ----------------------------------------------
199
200   SMESH_subMesh* srcSubMesh = srcMesh->GetSubMesh( srcEdge );
201   //SMESH_subMesh* tgtSubMesh = tgtMesh->GetSubMesh( tgtEdge );
202
203   if ( tgtMesh == srcMesh ) {
204     if ( !TAssocTool::MakeComputed( srcSubMesh ))
205       return error(COMPERR_BAD_INPUT_MESH,"Source mesh not computed");
206   }
207   else {
208     if ( !srcSubMesh->IsMeshComputed() )
209       return error(COMPERR_BAD_INPUT_MESH,"Source mesh not computed");
210   }
211   // -----------------------------------------------
212   // Find out nodes distribution on the source edge
213   // -----------------------------------------------
214
215   double srcLength = EdgeLength( srcEdge );
216   double tgtLength = EdgeLength( tgtEdge );
217   
218   vector< double > params; // sorted parameters of nodes on the source edge
219   if ( !SMESH_Algo::GetNodeParamOnEdge( srcMesh->GetMeshDS(), srcEdge, params ))
220     return error(COMPERR_BAD_INPUT_MESH,"Bad node parameters on the source edge");
221
222   int i, nbNodes = params.size();
223
224   vector< double > lengths( nbNodes - 1 ); // lengths of segments of the source edge
225   if ( srcLength > 0 )
226   {
227     BRepAdaptor_Curve curveAdaptor( srcEdge );
228     for ( i = 1; i < nbNodes; ++i )
229       lengths[ i-1 ] = GCPnts_AbscissaPoint::Length( curveAdaptor, params[i-1], params[i]);
230   }
231   else // degenerated source edge
232   {
233     for ( i = 1; i < nbNodes; ++i )
234       lengths[ i-1 ] = params[i] - params[i-1];
235     srcLength = params.back() - params[0];
236   }
237
238   bool reverse = ( srcV[0].IsSame( shape2ShapeMap( tgtV[1] )));
239   if ( shape2ShapeMap.IsBound( tgtEdge )) // case of closed edge
240     reverse = ( shape2ShapeMap( tgtEdge ).Orientation() == TopAbs_REVERSED );
241   if ( reverse ) // reverse lengths of segments
242     std::reverse( lengths.begin(), lengths.end() );
243
244   // ----------
245   // Make mesh
246   // ----------
247
248   // vector of target nodes
249   vector< const SMDS_MeshNode* > nodes ( nbNodes );
250
251   // Get the first and last nodes
252   nodes.front() = VertexNode( tgtV[0], meshDS );
253   nodes.back()  = VertexNode( tgtV[1], meshDS );
254   if ( !nodes.front() || !nodes.back() )
255     return error(COMPERR_BAD_INPUT_MESH,"No node on vertex");
256
257   // Compute parameters on the target edge and make internal nodes
258   // --------------------------------------------------------------
259
260   vector< double > tgtParams( nbNodes );
261
262   BRep_Tool::Range( tgtEdge, tgtParams.front(), tgtParams.back() );
263   if ( tgtLength <= 0 )
264     tgtLength = tgtParams.back() - tgtParams.front();
265   double dl = tgtLength / srcLength;
266
267   if ( tgtLength > 0 )
268   {
269     BRepAdaptor_Curve curveAdaptor( tgtEdge );
270
271     // compute params on internal nodes
272     for ( i = 1; i < nbNodes - 1; ++i )
273     {
274       // computes a point on a <curveAdaptor> at the given distance
275       // from the point at given parameter.
276       GCPnts_AbscissaPoint Discret( curveAdaptor, dl * lengths[ i-1 ], tgtParams[ i-1 ] );
277       if ( !Discret.IsDone() )
278         return error(dfltErr(),"GCPnts_AbscissaPoint failed");
279       tgtParams[ i ] = Discret.Parameter();
280     }
281     // make internal nodes 
282     for ( i = 1; i < nbNodes - 1; ++i )
283     {
284       gp_Pnt P = curveAdaptor.Value( tgtParams[ i ]);
285       SMDS_MeshNode* node = meshDS->AddNode(P.X(), P.Y(), P.Z());
286       meshDS->SetNodeOnEdge( node, tgtEdge, tgtParams[ i ]);
287       nodes[ i ] = node;
288     }
289   }
290   else // degenerated target edge
291   {
292     // compute params and make internal nodes
293     gp_Pnt P = BRep_Tool::Pnt( tgtV[0] );
294
295     for ( i = 1; i < nbNodes - 1; ++i )
296     {
297       SMDS_MeshNode* node = meshDS->AddNode(P.X(), P.Y(), P.Z());
298       tgtParams[ i ] = tgtParams[ i-1 ] + dl * lengths[ i-1 ];
299       meshDS->SetNodeOnEdge( node, tgtEdge, tgtParams[ i ]);
300       nodes[ i ] = node;
301     }
302   }
303
304   // Quadratic mesh?
305   // ----------------
306
307   bool quadratic = false;
308   SMDS_ElemIteratorPtr elemIt = srcSubMesh->GetSubMeshDS()->GetElements();
309   if ( elemIt->more() )
310     quadratic = elemIt->next()->IsQuadratic();
311   else {
312     SMDS_NodeIteratorPtr nodeIt = srcSubMesh->GetSubMeshDS()->GetNodes();
313     while ( nodeIt->more() && !quadratic )
314       quadratic = SMESH_MesherHelper::IsMedium( nodeIt->next() );
315   }
316   // enough nodes to make all edges quadratic?
317   if ( quadratic && ( nbNodes < 3 || ( nbNodes % 2 != 1 )))
318     return error(COMPERR_BAD_INPUT_MESH,
319                  SMESH_Comment("Wrong number of nodes to make quadratic mesh: ")<<nbNodes);
320
321   // Create edges
322   // -------------
323
324   SMDS_MeshElement* edge = 0;
325   int di = quadratic ? 2 : 1;
326   for ( i = di; i < nbNodes; i += di)
327   {
328     if ( quadratic )
329       edge = meshDS->AddEdge( nodes[i-2], nodes[i], nodes[i-1] );
330     else
331       edge = meshDS->AddEdge( nodes[i-1], nodes[i] );
332     meshDS->SetMeshElementOnShape(edge, tgtEdge );
333   }
334
335   return true;
336 }
337
338 //=============================================================================
339 /*!
340  * \brief Sets a default event listener to submesh of the source edge
341   * \param subMesh - submesh where algo is set
342  *
343  * This method is called when a submesh gets HYP_OK algo_state.
344  * After being set, event listener is notified on each event of a submesh.
345  * Arranges that CLEAN event is translated from source submesh to
346  * the submesh
347  */
348 //=============================================================================
349
350 void StdMeshers_Projection_1D::SetEventListener(SMESH_subMesh* subMesh)
351 {
352   TAssocTool::SetEventListener( subMesh,
353                                 _sourceHypo->GetSourceEdge(),
354                                 _sourceHypo->GetSourceMesh() );
355 }