1 // Copyright (C) 2007-2013 CEA/DEN, EDF R&D
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.
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.
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
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 // Author : Anthony Geay (CEA/DEN)
20 #ifndef __INTERPOLATION3D_TXX__
21 #define __INTERPOLATION3D_TXX__
23 #include "Interpolation3D.hxx"
24 #include "Interpolation.txx"
25 #include "MeshElement.txx"
26 #include "TransformedTriangle.hxx"
27 #include "PolyhedronIntersectorP0P0.txx"
28 #include "PointLocator3DIntersectorP0P0.txx"
29 #include "PolyhedronIntersectorP0P1.txx"
30 #include "PointLocator3DIntersectorP0P1.txx"
31 #include "PolyhedronIntersectorP1P0.txx"
32 #include "PolyhedronIntersectorP1P0Bary.txx"
33 #include "PointLocator3DIntersectorP1P0.txx"
34 #include "PolyhedronIntersectorP1P1.txx"
35 #include "PointLocator3DIntersectorP1P1.txx"
36 #include "Barycentric3DIntersectorP1P1.txx"
38 /// If defined, use recursion to traverse the binary search tree, else use the BBTree class
39 //#define USE_RECURSIVE_BBOX_FILTER
41 #ifdef USE_RECURSIVE_BBOX_FILTER
42 #include "MeshRegion.txx"
43 #include "RegionNode.hxx"
46 #else // use BBTree class
52 namespace INTERP_KERNEL
55 * Calculates the matrix of volumes of intersection between the elements of srcMesh and the elements of targetMesh.
56 * The calculation is done in two steps. First a filtering process reduces the number of pairs of elements for which the
57 * calculation must be carried out by eliminating pairs that do not intersect based on their bounding boxes. Then, the
58 * volume of intersection is calculated by an object of type Intersector3D for the remaining pairs, and entered into the
59 * intersection matrix.
61 * The matrix is partially sparse : it is a vector of maps of integer - double pairs.
62 * It can also be an INTERP_KERNEL::Matrix object.
63 * The length of the vector is equal to the number of target elements - for each target element there is a map, regardless
64 * of whether the element intersects any source elements or not. But in the maps there are only entries for those source elements
65 * which have a non-zero intersection volume with the target element. The vector has indices running from
66 * 0 to (nb target elements - 1), meaning that the map for target element i is stored at index i - 1. In the maps, however,
67 * the indexing is more natural : the intersection volume of the target element i with source element j is found at matrix[i-1][j].
70 * @param srcMesh 3-dimensional source mesh
71 * @param targetMesh 3-dimesional target mesh, containing only tetraedra
72 * @param result matrix in which the result is stored
75 template<class MyMeshType, class MatrixType>
76 int Interpolation3D::interpolateMeshes(const MyMeshType& srcMesh, const MyMeshType& targetMesh, MatrixType& result, const char *method)
78 typedef typename MyMeshType::MyConnType ConnType;
79 // create MeshElement objects corresponding to each element of the two meshes
80 const unsigned long numSrcElems = srcMesh.getNumberOfElements();
81 const unsigned long numTargetElems = targetMesh.getNumberOfElements();
83 LOG(2, "Source mesh has " << numSrcElems << " elements and target mesh has " << numTargetElems << " elements ");
85 std::vector<MeshElement<ConnType>*> srcElems(numSrcElems);
86 std::vector<MeshElement<ConnType>*> targetElems(numTargetElems);
88 std::map<MeshElement<ConnType>*, int> indices;
90 for(unsigned long i = 0 ; i < numSrcElems ; ++i)
91 srcElems[i] = new MeshElement<ConnType>(i, srcMesh);
93 for(unsigned long i = 0 ; i < numTargetElems ; ++i)
94 targetElems[i] = new MeshElement<ConnType>(i, targetMesh);
96 Intersector3D<MyMeshType,MatrixType>* intersector=0;
97 std::string methC = InterpolationOptions::filterInterpolationMethod(method);
100 switch(InterpolationOptions::getIntersectionType())
103 intersector=new PolyhedronIntersectorP0P0<MyMeshType,MatrixType>(targetMesh, srcMesh, getSplittingPolicy());
106 intersector=new PointLocator3DIntersectorP0P0<MyMeshType,MatrixType>(targetMesh, srcMesh, getPrecision());
109 throw INTERP_KERNEL::Exception("Invalid 3D intersection type for P0P0 interp specified : must be Triangle or PointLocator.");
112 else if(methC=="P0P1")
114 switch(InterpolationOptions::getIntersectionType())
117 intersector=new PolyhedronIntersectorP0P1<MyMeshType,MatrixType>(targetMesh, srcMesh, getSplittingPolicy());
120 intersector=new PointLocator3DIntersectorP0P1<MyMeshType,MatrixType>(targetMesh, srcMesh, getPrecision());
123 throw INTERP_KERNEL::Exception("Invalid 3D intersection type for P0P1 interp specified : must be Triangle or PointLocator.");
126 else if(methC=="P1P0")
128 switch(InterpolationOptions::getIntersectionType())
131 intersector=new PolyhedronIntersectorP1P0<MyMeshType,MatrixType>(targetMesh, srcMesh, getSplittingPolicy());
134 intersector=new PointLocator3DIntersectorP1P0<MyMeshType,MatrixType>(targetMesh, srcMesh, getPrecision());
137 intersector=new PolyhedronIntersectorP1P0Bary<MyMeshType,MatrixType>(targetMesh, srcMesh, getSplittingPolicy());
140 throw INTERP_KERNEL::Exception("Invalid 3D intersection type for P1P0 interp specified : must be Triangle, PointLocator or Barycentric.");
143 else if(methC=="P1P1")
145 switch(InterpolationOptions::getIntersectionType())
148 intersector=new PolyhedronIntersectorP1P1<MyMeshType,MatrixType>(targetMesh, srcMesh, getSplittingPolicy());
151 intersector=new PointLocator3DIntersectorP1P1<MyMeshType,MatrixType>(targetMesh, srcMesh, getPrecision());
154 intersector=new Barycentric3DIntersectorP1P1<MyMeshType,MatrixType>(targetMesh, srcMesh, getPrecision());
157 throw INTERP_KERNEL::Exception("Invalid 3D intersection type for P1P1 interp specified : must be Triangle or PointLocator.");
161 throw Exception("Invalid method choosed must be in \"P0P0\", \"P0P1\", \"P1P0\" or \"P1P1\".");
162 // create empty maps for all source elements
163 result.resize(intersector->getNumberOfRowsOfResMatrix());
165 #ifdef USE_RECURSIVE_BBOX_FILTER
168 * Performs a depth-first search over srcMesh, using bounding boxes to recursively eliminate the elements of targetMesh
169 * which cannot intersect smaller and smaller regions of srcMesh. At each level, each region is divided in two, forming
170 * a binary search tree with leaves consisting of only one element of the source mesh together with the elements of the
171 * target mesh that can intersect it. The recursion is implemented with a stack of RegionNodes, each one containing a
172 * source region and a target region. Each region has an associated bounding box and a vector of pointers to the elements
173 * that belong to it. Each MeshElement contains a bounding box and the global number of the corresponding element in the mesh.
176 // create initial RegionNode and fill up its source region with all the source mesh elements and
177 // its target region with all the target mesh elements whose bounding box
178 // intersects that of the source region
180 RegionNode<ConnType>* firstNode = new RegionNode<ConnType>();
182 MeshRegion<ConnType>& srcRegion = firstNode->getSrcRegion();
184 for(unsigned long i = 0 ; i < numSrcElems ; ++i)
186 srcRegion.addElement(srcElems[i], srcMesh);
189 MeshRegion<ConnType>& targetRegion = firstNode->getTargetRegion();
191 for(unsigned long i = 0 ; i < numTargetElems ; ++i)
193 if(!srcRegion.isDisjointWithElementBoundingBox( *(targetElems[i]) ))
195 targetRegion.addElement(targetElems[i], targetMesh);
199 // Using a stack, descend recursively, creating at each step two new RegionNodes having as source region the left and
200 // right part of the source region of the current node (created using MeshRegion::split()) and as target region all the
201 // elements of the target mesh whose bounding box intersects the corresponding part
202 // Continue until the source region contains only one element, at which point the intersection volumes are
203 // calculated with all the remaining target mesh elements and stored in the matrix if they are non-zero.
205 std::stack< RegionNode<ConnType>* > nodes;
206 nodes.push(firstNode);
208 while(!nodes.empty())
210 RegionNode<ConnType>* currNode = nodes.top();
212 LOG(4, "Popping node ");
214 if(currNode->getTargetRegion().getNumberOfElements() == 1)
217 LOG(4, " - One element");
219 MeshElement<ConnType>* targetElement = *(currNode->getTargetRegion().getBeginElements());
220 std::vector<ConnType> intersectElems;
221 for(typename std::vector< MeshElement<ConnType>* >::const_iterator iter = currNode->getSrcRegion().getBeginElements();iter != currNode->getSrcRegion().getEndElements();++iter)
222 intersectElems.push_back((*iter)->getIndex());
223 intersector->intersectCells(targetElement->getIndex(),intersectElems,result);
228 LOG(4, " - Recursion");
230 RegionNode<ConnType>* leftNode = new RegionNode<ConnType>();
231 RegionNode<ConnType>* rightNode = new RegionNode<ConnType>();
233 // split current source region
235 static BoundingBox::BoxCoord axis = BoundingBox::XMAX;
237 currNode->getTargetRegion().split(leftNode->getTargetRegion(), rightNode->getTargetRegion(), axis, targetMesh);
239 LOG(5, "After split, left target region has " << leftNode->getTargetRegion().getNumberOfElements()
240 << " elements and right target region has " << rightNode->getTargetRegion().getNumberOfElements()
243 // ugly hack to avoid problem with enum which does not start at 0
244 // I guess I ought to implement ++ for it instead ...
245 // Anyway, it basically chooses the next axis, cyclically
246 axis = (axis != BoundingBox::ZMAX) ? static_cast<BoundingBox::BoxCoord>(axis + 1) : BoundingBox::XMAX;
248 // add source elements of current node that overlap the target regions of the new nodes
249 LOG(5, " -- Adding source elements");
250 int numLeftElements = 0;
251 int numRightElements = 0;
252 for(typename std::vector<MeshElement<ConnType>*>::const_iterator iter = currNode->getSrcRegion().getBeginElements() ;
253 iter != currNode->getSrcRegion().getEndElements() ; ++iter)
255 LOG(6, " --- New target node");
257 if(!leftNode->getTargetRegion().isDisjointWithElementBoundingBox(**iter))
259 leftNode->getSrcRegion().addElement(*iter, srcMesh);
263 if(!rightNode->getTargetRegion().isDisjointWithElementBoundingBox(**iter))
265 rightNode->getSrcRegion().addElement(*iter, srcMesh);
271 LOG(5, "Left src region has " << numLeftElements << " elements and right src region has "
272 << numRightElements << " elements");
274 // push new nodes on stack
275 if(numLeftElements != 0)
277 nodes.push(leftNode);
284 if(numRightElements != 0)
286 nodes.push(rightNode);
294 // all nodes are deleted here
297 LOG(4, "Next iteration. Nodes left : " << nodes.size());
302 // create BBTree structure
303 // - get bounding boxes
304 double* bboxes = new double[6 * numSrcElems];
305 int* srcElemIdx = new int[numSrcElems];
306 for(unsigned long i = 0; i < numSrcElems ; ++i)
308 // get source bboxes in right order
309 const BoundingBox* box = srcElems[i]->getBoundingBox();
310 bboxes[6*i+0] = box->getCoordinate(BoundingBox::XMIN);
311 bboxes[6*i+1] = box->getCoordinate(BoundingBox::XMAX);
312 bboxes[6*i+2] = box->getCoordinate(BoundingBox::YMIN);
313 bboxes[6*i+3] = box->getCoordinate(BoundingBox::YMAX);
314 bboxes[6*i+4] = box->getCoordinate(BoundingBox::ZMIN);
315 bboxes[6*i+5] = box->getCoordinate(BoundingBox::ZMAX);
317 // source indices have to begin with zero for BBox, I think
318 srcElemIdx[i] = srcElems[i]->getIndex();
321 BBTree<3,ConnType> tree(bboxes, srcElemIdx, 0, numSrcElems);
323 // for each target element, get source elements with which to calculate intersection
324 // - calculate intersection by calling intersectCells
325 for(unsigned long i = 0; i < numTargetElems; ++i)
327 const BoundingBox* box = targetElems[i]->getBoundingBox();
328 const int targetIdx = targetElems[i]->getIndex();
330 // get target bbox in right order
332 targetBox[0] = box->getCoordinate(BoundingBox::XMIN);
333 targetBox[1] = box->getCoordinate(BoundingBox::XMAX);
334 targetBox[2] = box->getCoordinate(BoundingBox::YMIN);
335 targetBox[3] = box->getCoordinate(BoundingBox::YMAX);
336 targetBox[4] = box->getCoordinate(BoundingBox::ZMIN);
337 targetBox[5] = box->getCoordinate(BoundingBox::ZMAX);
339 std::vector<ConnType> intersectElems;
341 tree.getIntersectingElems(targetBox, intersectElems);
343 if ( !intersectElems.empty() )
344 intersector->intersectCells(targetIdx,intersectElems,result);
348 delete [] srcElemIdx;
351 // free allocated memory
352 int ret=intersector->getNumberOfColsOfResMatrix();
356 for(unsigned long i = 0 ; i < numSrcElems ; ++i)
360 for(unsigned long i = 0 ; i < numTargetElems ; ++i)
362 delete targetElems[i];