Salome HOME
Merge from V6_5_BR 05/06/2012
[modules/smesh.git] / src / StdMeshers / StdMeshers_Projection_1D2D.cxx
1 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  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 // File      : StdMeshers_Projection_1D2D.cxx
23 // Module    : SMESH
24 // Author    : Edward AGAPOV (eap)
25 //
26 #include "StdMeshers_Projection_1D2D.hxx"
27
28 #include "SMESH_Gen.hxx"
29 #include "SMESH_MesherHelper.hxx"
30 #include "SMESH_subMeshEventListener.hxx"
31 #include "StdMeshers_FaceSide.hxx"
32 #include "StdMeshers_ProjectionSource2D.hxx"
33 #include "StdMeshers_ProjectionUtils.hxx"
34
35 #include <TopoDS.hxx>
36 #include <TopExp_Explorer.hxx>
37
38 using namespace std;
39
40 namespace
41 {
42   // --------------------------------------------------------------------------------
43   /*!
44    * \brief an event listener updating submehses of EDGEs according to
45    *        events on the target FACE submesh
46    */
47   struct EventProparatorToEdges : public SMESH_subMeshEventListener
48   {
49     EventProparatorToEdges(): SMESH_subMeshEventListener(/*isDeletable=*/false,
50                                                          "Projection_1D2D::EventProparatorToEdges")
51     {}
52     static EventProparatorToEdges* Instance() { static EventProparatorToEdges E; return &E; }
53
54     static void Set(SMESH_subMesh* faceSubMesh)
55     {
56       SMESH_subMeshEventListenerData* edgeSubMeshes =
57         new SMESH_subMeshEventListenerData(/*isDeletable=*/true);
58       SMESH_Mesh* mesh = faceSubMesh->GetFather();
59       TopExp_Explorer eExp( faceSubMesh->GetSubShape(), TopAbs_EDGE );
60       for ( ; eExp.More(); eExp.Next() )
61         edgeSubMeshes->mySubMeshes.push_back( mesh->GetSubMesh( eExp.Current() ));
62
63       // set a listener
64       faceSubMesh->SetEventListener( Instance(), edgeSubMeshes, faceSubMesh );
65     }
66   };
67   // --------------------------------------------------------------------------------
68   /*!
69    * \brief Structure used to temporary remove EventProparatorToEdges from faceSubMesh
70    *  in order to prevent propagation of CLEAN event from FACE to EDGEs during 
71    *  StdMeshers_Projection_1D2D::Compute(). The CLEAN event is emmited by Pattern mapper
72    * and causes removal of faces generated on adjacent FACEs.
73    */
74   struct UnsetterOfEventProparatorToEdges
75   {
76     SMESH_subMesh* _faceSubMesh;
77     UnsetterOfEventProparatorToEdges( SMESH_subMesh* faceSubMesh ):_faceSubMesh(faceSubMesh)
78     {
79       faceSubMesh->DeleteEventListener( EventProparatorToEdges::Instance() );
80     }
81     ~UnsetterOfEventProparatorToEdges()
82     {
83       EventProparatorToEdges::Set(_faceSubMesh);
84     }
85   };
86 }
87
88 //=======================================================================
89 //function : StdMeshers_Projection_1D2D
90 //purpose  : 
91 //=======================================================================
92
93 StdMeshers_Projection_1D2D::StdMeshers_Projection_1D2D(int hypId, int studyId, SMESH_Gen* gen)
94   :StdMeshers_Projection_2D(hypId, studyId, gen)
95 {
96   _name = "Projection_1D2D";
97   _requireDiscreteBoundary = false;
98   _supportSubmeshes = true;
99 }
100
101 //=======================================================================
102 //function : Compute
103 //purpose  : 
104 //=======================================================================
105
106 bool StdMeshers_Projection_1D2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theShape)
107 {
108   UnsetterOfEventProparatorToEdges eventBarrier( theMesh.GetSubMesh( theShape ));
109
110   if ( !StdMeshers_Projection_2D::Compute(theMesh, theShape))
111     return false;
112
113   SMESHDS_Mesh * meshDS = theMesh.GetMeshDS();
114
115   SMESHDS_SubMesh * faceSubMesh = meshDS->MeshElements( theShape );
116   if ( !faceSubMesh || faceSubMesh->NbElements() == 0 ) return false;
117   _quadraticMesh = faceSubMesh->GetElements()->next()->IsQuadratic();
118
119   SMESH_MesherHelper helper( theMesh );
120   helper.SetSubShape( theShape );
121
122   TopoDS_Face F = TopoDS::Face( theShape );
123   TError err;
124   TSideVector wires = StdMeshers_FaceSide::GetFaceWires( F, theMesh,
125                                                          /*ignoreMediumNodes=*/false, err);
126   if ( err && !err->IsOK() )
127     return error( err );
128
129   for ( size_t iWire = 0; iWire < wires.size(); ++iWire )
130   {
131     vector<const SMDS_MeshNode*> nodes = wires[ iWire ]->GetOrderedNodes();
132     if ( nodes.empty() )
133       return error("Wrong nodes on a wire");
134
135     // check that all nodes are shared by faces generated on F
136     for ( size_t i = 0; i < nodes.size(); ++i )
137     {
138       SMDS_ElemIteratorPtr fIt = nodes[i]->GetInverseElementIterator(SMDSAbs_Face);
139       bool faceFound = false;
140       while ( !faceFound && fIt->more() )
141         faceFound = ( helper.GetSubShapeID() == fIt->next()->getshapeId() );
142       if ( !faceFound )
143         return error("The existing 1D mesh mismatches the generated 2D mesh");
144     }
145
146     const bool checkExisting = ( wires[ iWire ]->NbSegments() || helper.HasSeam() );
147
148     if ( _quadraticMesh )
149     {
150       for ( size_t i = 2; i < nodes.size(); i += 2 )
151       {
152         if ( checkExisting && meshDS->FindEdge( nodes[i-2], nodes[i], nodes[i-1]))
153           continue;
154         SMDS_MeshElement* e = meshDS->AddEdge( nodes[i-2], nodes[i], nodes[i-1] );
155         meshDS->SetMeshElementOnShape( e, nodes[i-1]->getshapeId() );
156       }
157     }
158     else
159     {
160       int edgeID = meshDS->ShapeToIndex( wires[ iWire ]->Edge(0) );
161       for ( size_t i = 1; i < nodes.size(); ++i )
162       {
163         if ( checkExisting && meshDS->FindEdge( nodes[i-1], nodes[i]))
164           continue;
165         SMDS_MeshElement* e = meshDS->AddEdge( nodes[i-1], nodes[i] );
166         if ( nodes[i-1]->getshapeId() != edgeID &&
167              nodes[i  ]->getshapeId() != edgeID )
168         {
169           edgeID = helper.GetMediumPos( nodes[i-1], nodes[i] ).first;
170           if ( edgeID < 1 ) edgeID = helper.GetSubShapeID();
171         }
172         meshDS->SetMeshElementOnShape( e, edgeID );
173       }
174     }
175   }   
176
177   return true;
178 }
179
180 //=======================================================================
181 //function : Evaluate
182 //purpose  : 
183 //=======================================================================
184
185 bool StdMeshers_Projection_1D2D::Evaluate(SMESH_Mesh&         theMesh,
186                                           const TopoDS_Shape& theShape,
187                                           MapShapeNbElems&    aResMap)
188 {
189   if ( !StdMeshers_Projection_2D::Evaluate(theMesh,theShape,aResMap))
190     return false;
191
192   TopoDS_Shape srcFace = _sourceHypo->GetSourceFace();
193   SMESH_Mesh * srcMesh = _sourceHypo->GetSourceMesh();
194   if ( !srcMesh ) srcMesh = & theMesh;
195   SMESH_subMesh* srcFaceSM = srcMesh->GetSubMesh( srcFace );
196
197   typedef StdMeshers_ProjectionUtils SPU;
198   SPU::TShapeShapeMap shape2ShapeMap;
199   SPU::InitVertexAssociation( _sourceHypo, shape2ShapeMap );
200   if ( !SPU::FindSubShapeAssociation( theShape, &theMesh, srcFace, srcMesh, shape2ShapeMap))
201     return error(COMPERR_BAD_SHAPE,"Topology of source and target faces seems different" );
202
203   MapShapeNbElems srcResMap;
204   if ( !srcFaceSM->IsMeshComputed() )
205     _gen->Evaluate( *srcMesh, srcFace, srcResMap);
206
207   SMESH_subMeshIteratorPtr smIt = srcFaceSM->getDependsOnIterator(/*includeSelf=*/false,
208                                                                   /*complexShapeFirst=*/true);
209   while ( smIt->more() )
210   {
211     SMESH_subMesh* srcSM = smIt->next();
212     TopAbs_ShapeEnum shapeType = srcSM->GetSubShape().ShapeType();
213     if ( shapeType == TopAbs_EDGE )
214     {
215       std::vector<int> aVec;
216       SMESHDS_SubMesh* srcSubMeshDS = srcSM->GetSubMeshDS();
217       if ( srcSubMeshDS && srcSubMeshDS->NbElements() )
218       {
219         aVec.resize(SMDSEntity_Last, 0);
220         SMDS_ElemIteratorPtr eIt = srcSubMeshDS->GetElements();
221         _quadraticMesh = ( eIt->more() && eIt->next()->IsQuadratic() );
222
223         aVec[SMDSEntity_Node] = srcSubMeshDS->NbNodes();
224         aVec[_quadraticMesh ? SMDSEntity_Quad_Edge : SMDSEntity_Edge] = srcSubMeshDS->NbElements();
225       }
226       else
227       {
228         if ( srcResMap.empty() )
229           if ( !_gen->Evaluate( *srcMesh, srcSM->GetSubShape(), srcResMap ))
230             return error(COMPERR_BAD_INPUT_MESH,"Source mesh not evaluatable");
231         aVec = srcResMap[ srcSM ];
232         if ( aVec.empty() )
233           return error(COMPERR_BAD_INPUT_MESH,"Source mesh is wrongly evaluated");
234       }
235       TopoDS_Shape tgtEdge = shape2ShapeMap( srcSM->GetSubShape(), /*isSrc=*/true  );
236       SMESH_subMesh* tgtSM = theMesh.GetSubMesh( tgtEdge );
237       aResMap.insert(std::make_pair(tgtSM,aVec));
238     }
239     if ( shapeType == TopAbs_VERTEX ) break;
240   }
241
242   return true;
243 }
244
245 //=======================================================================
246 //function : SetEventListener
247 //purpose  : Sets a default event listener to submesh of the source face.
248 //           faceSubMesh - submesh where algo is set
249 // After being set, event listener is notified on each event of a submesh.
250 // This method is called when a submesh gets HYP_OK algo_state.
251 // Arranges that CLEAN event is translated from source submesh to
252 // the faceSubMesh submesh.
253 //=======================================================================
254
255 void StdMeshers_Projection_1D2D::SetEventListener(SMESH_subMesh* faceSubMesh)
256 {
257   // set a listener of events on a source submesh
258   StdMeshers_Projection_2D::SetEventListener(faceSubMesh);
259
260   // set a listener to the target FACE submesh in order to update submehses
261   // of EDGEs according to events on the target FACE submesh
262   EventProparatorToEdges::Set( faceSubMesh );
263 }
264