PrimitivePatchProjectPoints.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 Description
25  For every point on the patch find the closest face on the target side.
26  Return a target face label for each patch point
27 
28 \*---------------------------------------------------------------------------*/
29 
30 #include "boolList.H"
31 #include "PointHit.H"
32 #include "objectHit.H"
33 #include "bandCompression.H"
34 
35 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
36 
37 template
38 <
39  class Face,
40  template<class> class FaceList,
41  class PointField,
42  class PointType
43 >
44 template<class ToPatch>
48 (
49  const ToPatch& targetPatch,
50  const Field<PointType>& projectionDirection,
51  const intersection::algorithm alg,
52  const intersection::direction dir
53 ) const
54 {
55  // The current patch is slave, i.e. it is being projected onto the target
56 
57  if (projectionDirection.size() != nPoints())
58  {
60  << "Projection direction field does not correspond to "
61  << "patch points." << endl
62  << "Size: " << projectionDirection.size()
63  << " Number of points: " << nPoints()
64  << abort(FatalError);
65  }
66 
67  const labelList& slavePointOrder = localPointOrder();
68 
69  const labelList& slaveMeshPoints = meshPoints();
70 
71  // Result
72  List<objectHit> result(nPoints());
73 
74  const labelListList& masterFaceFaces = targetPatch.faceFaces();
75 
76  const ToPatch& masterFaces = targetPatch;
77 
78  const Field<PointType>& masterPoints = targetPatch.points();
79 
80  // Estimate face centre of target side
81  Field<PointType> masterFaceCentres(targetPatch.size());
82 
83  forAll(masterFaceCentres, facei)
84  {
85  masterFaceCentres[facei] =
86  average(masterFaces[facei].points(masterPoints));
87  }
88 
89  // Algorithm:
90  // Loop through all points of the slave side. For every point find the
91  // radius for the current contact face. If the contact point falls inside
92  // the face and the radius is smaller than for all neighbouring faces,
93  // the contact is found. If not, visit the neighbour closest to the
94  // calculated contact point. If a single master face is visited more than
95  // twice, initiate n-squared search.
96 
97  label curFace = 0;
98  label nNSquaredSearches = 0;
99 
100  forAll(slavePointOrder, pointi)
101  {
102  // Pick up slave point and direction
103  const label curLocalPointLabel = slavePointOrder[pointi];
104 
105  const PointType& curPoint =
106  points_[slaveMeshPoints[curLocalPointLabel]];
107 
108  const PointType& curProjectionDir =
109  projectionDirection[curLocalPointLabel];
110 
111  bool closer;
112 
113  boolList visitedTargetFace(targetPatch.size(), false);
114  bool doNSquaredSearch = false;
115 
116  bool foundEligible = false;
117 
118  scalar sqrDistance = great;
119 
120  // Force the full search for the first point to ensure good
121  // starting face
122  if (pointi == 0)
123  {
124  doNSquaredSearch = true;
125  }
126  else
127  {
128  do
129  {
130  closer = false;
131  doNSquaredSearch = false;
132 
133  // Calculate intersection with curFace
134  PointHit<PointType> curHit =
135  masterFaces[curFace].ray
136  (
137  curPoint,
138  curProjectionDir,
139  masterPoints,
140  alg,
141  dir
142  );
143 
144  visitedTargetFace[curFace] = true;
145 
146  if (curHit.hit())
147  {
148  result[curLocalPointLabel] = objectHit(true, curFace);
149 
150  break;
151  }
152  else
153  {
154  // If a new miss is eligible, it is closer than
155  // any previous eligible miss (due to surface walk)
156 
157  // Only grab the miss if it is eligible
158  if (curHit.eligibleMiss())
159  {
160  foundEligible = true;
161  result[curLocalPointLabel] = objectHit(false, curFace);
162  }
163 
164  // Find the next likely face for intersection
165 
166  // Calculate the miss point on the plane of the
167  // face. This is cooked (illogical!) for fastest
168  // surface walk.
169  //
170  PointType missPlanePoint =
171  curPoint + curProjectionDir*curHit.distance();
172 
173  const labelList& masterNbrs = masterFaceFaces[curFace];
174 
175  sqrDistance =
176  magSqr(missPlanePoint - masterFaceCentres[curFace]);
177 
178  forAll(masterNbrs, nbrI)
179  {
180  if
181  (
182  magSqr
183  (
184  missPlanePoint
185  - masterFaceCentres[masterNbrs[nbrI]]
186  )
187  <= sqrDistance
188  )
189  {
190  closer = true;
191  curFace = masterNbrs[nbrI];
192  }
193  }
194 
195  if (visitedTargetFace[curFace])
196  {
197  // This face has already been visited.
198  // Execute n-squared search
199  doNSquaredSearch = true;
200  break;
201  }
202  }
203 
204  if (debug) Info<< ".";
205  } while (closer);
206  }
207 
208  if
209  (
210  doNSquaredSearch || !foundEligible
211  )
212  {
213  nNSquaredSearches++;
214 
215  if (debug)
216  {
217  Info<< "p " << curLocalPointLabel << ": ";
218  }
219 
220  result[curLocalPointLabel] = objectHit(false, -1);
221  scalar minDistance = great;
222 
223  forAll(masterFaces, facei)
224  {
225  PointHit<PointType> curHit =
226  masterFaces[facei].ray
227  (
228  curPoint,
229  curProjectionDir,
230  masterPoints,
231  alg,
232  dir
233  );
234 
235  if (curHit.hit())
236  {
237  result[curLocalPointLabel] = objectHit(true, facei);
238  curFace = facei;
239 
240  break;
241  }
242  else if (curHit.eligibleMiss())
243  {
244  // Calculate min distance
245  scalar missDist =
246  Foam::mag(curHit.missPoint() - curPoint);
247 
248  if (missDist < minDistance)
249  {
250  minDistance = missDist;
251 
252  result[curLocalPointLabel] = objectHit(false, facei);
253  curFace = facei;
254  }
255  }
256  }
257 
258  if (debug)
259  {
260  Info<< result[curLocalPointLabel] << nl;
261  }
262  }
263  else
264  {
265  if (debug) Info<< "x";
266  }
267  }
268 
269  if (debug)
270  {
271  Info<< nl << "Executed " << nNSquaredSearches
272  << " n-squared searches out of total of "
273  << nPoints() << endl;
274  }
275 
276  return result;
277 }
278 
279 
280 template
281 <
282  class Face,
283  template<class> class FaceList,
284  class PointField,
285  class PointType
286 >
287 template<class ToPatch>
291 (
292  const ToPatch& targetPatch,
293  const Field<PointType>& projectionDirection,
294  const intersection::algorithm alg,
295  const intersection::direction dir
296 ) const
297 {
298  // The current patch is slave, i.e. it is being projected onto the target
299 
300  if (projectionDirection.size() != this->size())
301  {
303  << "Projection direction field does not correspond to patch faces."
304  << endl << "Size: " << projectionDirection.size()
305  << " Number of points: " << this->size()
306  << abort(FatalError);
307  }
308 
309  labelList slaveFaceOrder = bandCompression(faceFaces());
310 
311  // calculate master face centres
312  Field<PointType> masterFaceCentres(targetPatch.size());
313 
314  const labelListList& masterFaceFaces = targetPatch.faceFaces();
315 
316  const ToPatch& masterFaces = targetPatch;
317 
318  const typename ToPatch::PointFieldType& masterPoints = targetPatch.points();
319 
320  forAll(masterFaceCentres, facei)
321  {
322  masterFaceCentres[facei] =
323  masterFaces[facei].centre(masterPoints);
324  }
325 
326  // Result
327  List<objectHit> result(this->size());
328 
330  *this;
331 
332  const PointField& slaveGlobalPoints = points();
333 
334  // Algorithm:
335  // Loop through all points of the slave side. For every point find the
336  // radius for the current contact face. If the contact point falls inside
337  // the face and the radius is smaller than for all neighbouring faces,
338  // the contact is found. If not, visit the neighbour closest to the
339  // calculated contact point. If a single master face is visited more than
340  // twice, initiate n-squared search.
341 
342  label curFace = 0;
343  label nNSquaredSearches = 0;
344 
345  forAll(slaveFaceOrder, facei)
346  {
347  // pick up slave point and direction
348  const label curLocalFaceLabel = slaveFaceOrder[facei];
349 
350  const point& curFaceCentre =
351  slaveFaces[curLocalFaceLabel].centre(slaveGlobalPoints);
352 
353  const vector& curProjectionDir =
354  projectionDirection[curLocalFaceLabel];
355 
356  bool closer;
357 
358  boolList visitedTargetFace(targetPatch.size(), false);
359  bool doNSquaredSearch = false;
360 
361  bool foundEligible = false;
362 
363  scalar sqrDistance = great;
364 
365  // Force the full search for the first point to ensure good
366  // starting face
367  if (facei == 0)
368  {
369  doNSquaredSearch = true;
370  }
371  else
372  {
373  do
374  {
375  closer = false;
376  doNSquaredSearch = false;
377 
378  // Calculate intersection with curFace
379  PointHit<PointType> curHit =
380  masterFaces[curFace].ray
381  (
382  curFaceCentre,
383  curProjectionDir,
384  masterPoints,
385  alg,
386  dir
387  );
388 
389  visitedTargetFace[curFace] = true;
390 
391  if (curHit.hit())
392  {
393  result[curLocalFaceLabel] = objectHit(true, curFace);
394 
395  break;
396  }
397  else
398  {
399  // If a new miss is eligible, it is closer than
400  // any previous eligible miss (due to surface walk)
401 
402  // Only grab the miss if it is eligible
403  if (curHit.eligibleMiss())
404  {
405  foundEligible = true;
406  result[curLocalFaceLabel] = objectHit(false, curFace);
407  }
408 
409  // Find the next likely face for intersection
410 
411  // Calculate the miss point. This is
412  // cooked (illogical!) for fastest surface walk.
413  //
414  PointType missPlanePoint =
415  curFaceCentre + curProjectionDir*curHit.distance();
416 
417  sqrDistance =
418  magSqr(missPlanePoint - masterFaceCentres[curFace]);
419 
420  const labelList& masterNbrs = masterFaceFaces[curFace];
421 
422  forAll(masterNbrs, nbrI)
423  {
424  if
425  (
426  magSqr
427  (
428  missPlanePoint
429  - masterFaceCentres[masterNbrs[nbrI]]
430  )
431  <= sqrDistance
432  )
433  {
434  closer = true;
435  curFace = masterNbrs[nbrI];
436  }
437  }
438 
439  if (visitedTargetFace[curFace])
440  {
441  // This face has already been visited.
442  // Execute n-squared search
443  doNSquaredSearch = true;
444  break;
445  }
446  }
447 
448  if (debug) Info<< ".";
449  } while (closer);
450  }
451 
452  if (doNSquaredSearch || !foundEligible)
453  {
454  nNSquaredSearches++;
455 
456  if (debug)
457  {
458  Info<< "p " << curLocalFaceLabel << ": ";
459  }
460 
461  result[curLocalFaceLabel] = objectHit(false, -1);
462  scalar minDistance = great;
463 
464  forAll(masterFaces, facei)
465  {
466  PointHit<PointType> curHit =
467  masterFaces[facei].ray
468  (
469  curFaceCentre,
470  curProjectionDir,
471  masterPoints,
472  alg,
473  dir
474  );
475 
476  if (curHit.hit())
477  {
478  result[curLocalFaceLabel] = objectHit(true, facei);
479  curFace = facei;
480 
481  break;
482  }
483  else if (curHit.eligibleMiss())
484  {
485  // Calculate min distance
486  scalar missDist =
487  Foam::mag(curHit.missPoint() - curFaceCentre);
488 
489  if (missDist < minDistance)
490  {
491  minDistance = missDist;
492 
493  result[curLocalFaceLabel] = objectHit(false, facei);
494  curFace = facei;
495  }
496  }
497  }
498 
499  if (debug)
500  {
501  Info<< result[curLocalFaceLabel] << nl;
502  }
503  }
504  else
505  {
506  if (debug) Info<< "x";
507  }
508  }
509 
510  if (debug)
511  {
512  Info<< nl << "Executed " << nNSquaredSearches
513  << " n-squared searches out of total of "
514  << this->size() << endl;
515  }
516 
517  return result;
518 }
519 
520 
521 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:428
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
error FatalError
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:319
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:163
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:256
const Point & missPoint() const
Return miss point.
Definition: PointHit.H:145
A list of faces which address into the list of points.
The bandCompression function renumbers the addressing such that the band of the matrix is reduced...
const pointField & points
label nPoints
bool hit() const
Is there a hit.
Definition: PointHit.H:120
This class describes the interaction of a face and a point. It carries the info of a successful hit a...
Definition: PointHit.H:51
errorManip< error > abort(error &err)
Definition: errorManip.H:131
This class describes a combination of target object index and success flag.
Definition: objectHit.H:46
List< objectHit > projectFaceCentres(const ToPatch &targetPatch, const Field< PointType > &projectionDirection, const intersection::algorithm=intersection::FULL_RAY, const intersection::direction=intersection::VECTOR) const
Project vertices of patch onto another patch.
dimensioned< scalar > magSqr(const dimensioned< Type > &)
static const char nl
Definition: Ostream.H:265
List< objectHit > projectPoints(const ToPatch &targetPatch, const Field< PointType > &projectionDirection, const intersection::algorithm=intersection::FULL_RAY, const intersection::direction=intersection::VECTOR) const
Project vertices of patch onto another patch.
labelList bandCompression(const labelListList &addressing)
Renumbers the addressing to reduce the band of the matrix.
messageStream Info
tmp< GeometricField< Type, fvPatchField, volMesh > > average(const GeometricField< Type, fvsPatchField, surfaceMesh > &ssf)
Area-weighted average a surfaceField creating a volField.
Definition: fvcAverage.C:46
dimensioned< scalar > mag(const dimensioned< Type > &)
scalar distance() const
Return distance to hit.
Definition: PointHit.H:139
bool eligibleMiss() const
Is this an eligible miss.
Definition: PointHit.H:164