Salome HOME
Merge from V6_main_20120808 08Aug12
[modules/med.git] / src / INTERP_KERNEL / PointLocatorAlgos.txx
1 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19 #ifndef __POINTLOCATORALGOS_TXX__
20 #define __POINTLOCATORALGOS_TXX__
21
22 #include "InterpolationUtils.hxx"
23 #include "CellModel.hxx"
24 #include "BBTree.txx"
25
26 #include <list>
27 #include <set>
28 #include <limits>
29
30 namespace INTERP_KERNEL
31 {
32   class GenericPointLocatorAlgos
33   {
34   public:
35     virtual ~GenericPointLocatorAlgos() { }
36     virtual std::list<int> locates(const double* x, double eps) = 0;     
37   };
38         
39   template<class MyMeshType>
40   class PointLocatorAlgos: public GenericPointLocatorAlgos
41   {
42   private : 
43     double* _bb;
44     BBTree<MyMeshType::MY_SPACEDIM,typename MyMeshType::MyConnType>* _tree;
45     const MyMeshType& _mesh;
46   public:
47     PointLocatorAlgos(const MyMeshType& mesh):_mesh(mesh)
48     {
49       typedef typename MyMeshType::MyConnType ConnType;
50       const int SPACEDIM=MyMeshType::MY_SPACEDIM;
51       const NumberingPolicy numPol=MyMeshType::My_numPol;
52       int nelem = _mesh.getNumberOfElements();
53       _bb = new double[SPACEDIM*2*nelem];
54       const ConnType* conn = _mesh.getConnectivityPtr();
55       const ConnType* conn_index = _mesh.getConnectivityIndexPtr();
56       const double* coords=_mesh.getCoordinatesPtr();
57       for (int i=0; i<nelem; i++)
58         {
59           for (int idim=0; idim<SPACEDIM; idim++)
60             {
61               _bb[2*(i*SPACEDIM+idim)]=std::numeric_limits<double>::max();
62               _bb[2*(i*SPACEDIM+idim)+1]=-std::numeric_limits<double>::max();
63             }
64           for (int index= conn_index[i]; index < conn_index[i+1];index++)
65             {
66               //coordelem points to the coordinates of the current node of the i-th element
67               const double* coordelem = coords+OTT<ConnType,numPol>::ind2C(conn[OTT<ConnType,numPol>::ind2C(index)])*SPACEDIM;
68
69               //the bounding box is updated by checking wheher the node is at the min/max in exach dimension
70               for (int idim=0; idim<SPACEDIM;idim++)
71                 {
72                   _bb[2*(i*SPACEDIM+idim)]=(coordelem[idim]<_bb[2*(i*SPACEDIM+idim)])?coordelem[idim]:_bb[2*(i*SPACEDIM+idim)];
73                   _bb[2*(i*SPACEDIM+idim)+1]=(coordelem[idim]>_bb[2*(i*SPACEDIM+idim)+1])?coordelem[idim]:_bb[2*(i*SPACEDIM+idim)+1];
74                 }
75             }
76         }
77       _tree=new BBTree<SPACEDIM,typename MyMeshType::MyConnType>(_bb,0,0,nelem);
78     }
79
80     ~PointLocatorAlgos()
81     {
82       delete[] _bb;
83       delete _tree;
84     }
85         
86     //returns the list of elements that contains 
87     //the point pointed to by x
88     std::list<typename MyMeshType::MyConnType> locates(const double* x, double eps)
89     {
90       typedef typename MyMeshType::MyConnType ConnType;
91       const NumberingPolicy numPol=MyMeshType::My_numPol;
92       std::vector<ConnType> candidates;
93       _tree->getElementsAroundPoint(x,candidates);
94       std::list<ConnType> retlist;
95       for(unsigned int i=0; i< candidates.size(); i++)
96         {
97           int ielem=candidates[i];
98           if (elementContainsPoint(ielem,x,eps))
99             retlist.push_back(OTT<ConnType,numPol>::indFC(ielem));
100         }
101       return retlist;
102     }
103
104     static bool isElementContainsPointAlg2D(const double *ptToTest, const double *cellPts, int nbEdges, double eps)
105     {
106       /* with dimension 2, it suffices to check all the edges
107          and see if the sign of double products from the point
108          is always the same.
109                          C
110                         / \
111                        /   \
112              Xo       /     \ 
113                      A-------B
114        
115          here XA^XC and XC^XB have different signs*/
116       const int SPACEDIM=MyMeshType::MY_SPACEDIM;
117       int* sign = new int[nbEdges];
118       for (int iedge=0; iedge<nbEdges; iedge++)
119         {
120           const double* A=cellPts+SPACEDIM*iedge;
121           const double* B=cellPts+SPACEDIM*((iedge+1)%nbEdges);
122           double a=mon_determinant(ptToTest, A, B);
123           if(a<-eps)
124             sign[iedge]=-1;
125           else if(a>eps)
126             sign[iedge]=1;
127           else
128             sign[iedge]=0;
129         }
130       bool ret=decideFromSign(sign, nbEdges);
131       delete [] sign;
132       return ret;
133     }
134
135     static bool isElementContainsPointAlg3D(const double *ptToTest, const typename MyMeshType::MyConnType *conn_elem, int conn_elem_sz, const double *coords, const CellModel& cmType, double eps)
136     {
137       const int SPACEDIM=MyMeshType::MY_SPACEDIM;
138       typedef typename MyMeshType::MyConnType ConnType;
139       const NumberingPolicy numPol=MyMeshType::My_numPol;
140       
141       int nbfaces = cmType.getNumberOfSons2(conn_elem,conn_elem_sz);
142       int *sign = new int[nbfaces];
143       int *connOfSon = new int[conn_elem_sz];
144       for (int iface=0; iface<nbfaces; iface++)
145         {
146           NormalizedCellType typeOfSon;
147           cmType.fillSonCellNodalConnectivity2(iface,conn_elem,conn_elem_sz,connOfSon,typeOfSon);
148           const double* AA=coords+SPACEDIM*(OTT<ConnType,numPol>::coo2C(connOfSon[0]));
149           const double* BB=coords+SPACEDIM*(OTT<ConnType,numPol>::coo2C(connOfSon[1]));
150           const double* CC=coords+SPACEDIM*(OTT<ConnType,numPol>::coo2C(connOfSon[2]));                                                       
151           double Vol=triple_product(AA,BB,CC,ptToTest);
152           if (Vol<-eps)
153             sign[iface]=-1;
154           else if (Vol>eps)
155             sign[iface]=1;
156               else
157                 sign[iface]=0;
158         }
159       bool ret=decideFromSign(sign, nbfaces);
160       delete [] sign;
161       delete [] connOfSon;
162       return ret;
163     }
164
165     static bool isElementContainsPoint(const double *ptToTest, NormalizedCellType type, const double *coords, const typename MyMeshType::MyConnType *conn_elem, int conn_elem_sz, double eps)
166     {
167       const int SPACEDIM=MyMeshType::MY_SPACEDIM;
168       typedef typename MyMeshType::MyConnType ConnType;
169       const NumberingPolicy numPol=MyMeshType::My_numPol;
170
171       const CellModel& cmType=CellModel::GetCellModel(type);
172       //
173       if (SPACEDIM==2)
174         {
175           int nbEdges=cmType.getNumberOfSons();
176           double *pts = new double[nbEdges*SPACEDIM];
177           for (int iedge=0; iedge<nbEdges; iedge++)
178             {
179               const double* a=coords+SPACEDIM*(OTT<ConnType,numPol>::ind2C(conn_elem[iedge]));
180               std::copy(a,a+SPACEDIM,pts+iedge*SPACEDIM);
181             }
182           bool ret=isElementContainsPointAlg2D(ptToTest,pts,nbEdges,eps);
183           delete [] pts;
184           return ret;
185         }
186                         
187       if (SPACEDIM==3)
188         {
189           return isElementContainsPointAlg3D(ptToTest,conn_elem,conn_elem_sz,coords,cmType,eps);
190         }
191
192       if(SPACEDIM==1)
193         {
194           double p1=coords[(OTT<ConnType,numPol>::ind2C(conn_elem[0]))];
195           double p2=coords[(OTT<ConnType,numPol>::ind2C(conn_elem[1]))];
196           double delta=fabs(p1-p2)+eps;
197           double val=*ptToTest-std::min(p1,p2);
198           return val>-eps && val<delta;
199         }
200       throw INTERP_KERNEL::Exception("Invalid spacedim detected ! Managed spaceDim are 2 and 3 !");
201     }
202         
203     bool elementContainsPoint(typename MyMeshType::MyConnType i, const double* x, double eps)
204     {
205       //as i is extracted from the BBTRee, it is already in C numbering
206       //it is not necessary to convert it from F to C
207       typedef typename MyMeshType::MyConnType ConnType;
208       const NumberingPolicy numPol=MyMeshType::My_numPol;
209       
210       const double* coords= _mesh.getCoordinatesPtr();
211       const ConnType* conn=_mesh.getConnectivityPtr();
212       const ConnType* conn_index= _mesh.getConnectivityIndexPtr();
213       const ConnType* conn_elem=conn+OTT<ConnType,numPol>::ind2C(conn_index[i]);
214       int conn_elem_sz=conn_index[i+1]-conn_index[i];
215       NormalizedCellType type=_mesh.getTypeOfElement(OTT<ConnType,numPol>::indFC(i));
216       return isElementContainsPoint(x,type,coords,conn_elem,conn_elem_sz,eps);
217     }
218                 
219     static bool decideFromSign(const int* sign, int nbelem)
220     {
221       int min_sign = 1;
222       int max_sign = -1;
223       for (int i=0; i<nbelem;i++)
224         {
225           min_sign=(sign[i]<min_sign)?sign[i]:min_sign;
226           max_sign=(sign[i]>max_sign)?sign[i]:max_sign;
227         }
228       return (min_sign!=-1 || max_sign!=1);     
229     }
230   };
231
232   template<class MyMeshType>
233   class PointLocatorInSimplex : public PointLocatorAlgos<MyMeshType>
234   {
235     const MyMeshType& _mesh;
236   public:
237     PointLocatorInSimplex(const MyMeshType& mesh)
238       :PointLocatorAlgos<MyMeshType>(mesh),_mesh(mesh)
239     {
240     }
241
242     //================================================================================
243     /*!
244      * \brief Returns nodes composing the simplex the point x is in
245      */
246     //================================================================================
247
248     virtual std::list<int> locates(const double* x, double eps)
249     {
250       typedef typename MyMeshType::MyConnType ConnType;
251       const NumberingPolicy numPol=MyMeshType::My_numPol;
252
253       std::list<int> simplexNodes;
254       std::list<int> candidates = PointLocatorAlgos<MyMeshType>::locates(x,eps);
255       std::list<int>::iterator eIt = candidates.begin();
256       for ( ; eIt != candidates.end(); ++eIt )
257         {
258           const int i = OTT<ConnType,numPol>::ind2C( *eIt );
259           const double* coords= _mesh.getCoordinatesPtr();
260           const ConnType* conn=_mesh.getConnectivityPtr();
261           const ConnType* conn_index= _mesh.getConnectivityIndexPtr();
262           const ConnType* conn_elem=conn+OTT<ConnType,numPol>::ind2C(conn_index[i]);
263           int conn_elem_sz=conn_index[i+1]-conn_index[i];
264           NormalizedCellType type=_mesh.getTypeOfElement(OTT<ConnType,numPol>::indFC(i));
265           CellModel cell = CellModel::GetCellModel(type);
266
267           if ( cell.isQuadratic() )
268             throw Exception("P2 not implemented yet");
269
270           if ( cell.isSimplex())
271             {
272               for ( int n = 0; n < conn_elem_sz; ++n )
273                 simplexNodes.push_back( conn_elem[ n ]);
274             }
275           else
276             {
277               NormalizedCellType simlexType = cell.getDimension()==3 ? NORM_TETRA4 : NORM_TRI3;
278               std::vector<int> sonNodes;
279               NormalizedCellType sonType;
280               const unsigned nbSons = cell.getNumberOfSons2( conn_elem, conn_elem_sz );
281               for ( unsigned s = 0; s < nbSons; ++s )
282                 {
283                   sonNodes.resize( cell.getNumberOfNodesConstituentTheSon2( s, conn_elem, conn_elem_sz ));
284                   cell.fillSonCellNodalConnectivity2( s, conn_elem, conn_elem_sz, &sonNodes[0], sonType );
285                   std::set<int> sonNodesSet( sonNodes.begin(), sonNodes.end() );
286
287                   std::set< std::set< ConnType > > checkedSonSimplex;
288                   for ( unsigned sn = 0; sn < sonNodes.size(); ++sn )
289                     {
290                       std::vector< ConnType > simplexConn( cell.getDimension() + 1 );
291                       unsigned n;
292                       for ( n = 0; n < cell.getDimension()-1; ++n )
293                         simplexConn[n] = sonNodes[ (sn+n) % sonNodes.size() ];
294
295                       for ( unsigned n2 = 0; n2 < sonNodes.size()-cell.getDimension()+1; ++n2 )
296                         {
297                           simplexConn[n] = sonNodes[ (sn+n+n2) % sonNodes.size() ];
298                           std::set< ConnType > sonSimplex( simplexConn.begin(), --simplexConn.end());
299                           if ( checkedSonSimplex.insert( sonSimplex ).second )
300                             {
301                               for ( unsigned cn = 0; cn < conn_elem_sz; ++cn )
302                                 if ( !sonNodesSet.count( conn_elem[cn] ))
303                                   {
304                                     simplexConn.back() = conn_elem[cn];
305                                     if ( this->isElementContainsPoint( x, simlexType, coords,
306                                                                        &simplexConn[0], simplexConn.size(), eps ))
307                                       {
308                                         simplexNodes.insert( simplexNodes.end(),
309                                                              simplexConn.begin(), simplexConn.end());
310                                         return simplexNodes;
311                                       }
312                                   }
313                             }
314                         }
315                     }
316                 }
317             }
318         }
319       return simplexNodes;
320     }
321
322   };
323 }
324
325 #endif