searchableSurfacesQueries.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2017 OpenFOAM Foundation
9  Copyright (C) 2015-2022 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
30 #include "ListOps.H"
31 #include "OFstream.H"
32 #include "meshTools.H"
33 #include "DynamicField.H"
34 #include "pointConstraint.H"
35 #include "plane.H"
36 
37 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
38 
39 namespace Foam
40 {
41  defineTypeNameAndDebug(searchableSurfacesQueries, 0);
42 }
43 
44 
45 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
46 
47 void Foam::searchableSurfacesQueries::mergeHits
48 (
49  const point& start,
50 
51  const label testI, // index of surface
52  const List<pointIndexHit>& surfHits, // hits on surface
53 
54  labelList& allSurfaces,
55  List<pointIndexHit>& allInfo,
56  scalarList& allDistSqr
57 )
58 {
59  // Given current set of hits (allSurfaces, allInfo) merge in those coming
60  // from surface surfI.
61 
62  // Precalculate distances
63  scalarList surfDistSqr(surfHits.size());
64  forAll(surfHits, i)
65  {
66  surfDistSqr[i] = surfHits[i].hitPoint().distSqr(start);
67  }
68 
69  forAll(surfDistSqr, i)
70  {
71  label index = findLower(allDistSqr, surfDistSqr[i]);
72 
73  // Check if equal to lower.
74  if (index >= 0)
75  {
76  // Same. Do not count.
77  //Pout<< "point:" << surfHits[i].point()
78  // << " considered same as:" << allInfo[index].point()
79  // << " within tol:" << mergeDist
80  // << endl;
81  }
82  else
83  {
84  // Check if equal to higher
85  label next = index + 1;
86 
87  if (next < allDistSqr.size())
88  {
89  //Pout<< "point:" << surfHits[i].point()
90  // << " considered same as:" << allInfo[next].point()
91  // << " within tol:" << mergeDist
92  // << endl;
93  }
94  else
95  {
96  // Insert after index
97  label sz = allSurfaces.size();
98  allSurfaces.setSize(sz+1);
99  allInfo.setSize(allSurfaces.size());
100  allDistSqr.setSize(allSurfaces.size());
101  // Make space.
102  for (label j = sz-1; j > index; --j)
103  {
104  allSurfaces[j+1] = allSurfaces[j];
105  allInfo[j+1] = allInfo[j];
106  allDistSqr[j+1] = allDistSqr[j];
107  }
108  // Insert new value
109  allSurfaces[index+1] = testI;
110  allInfo[index+1] = surfHits[i];
111  allDistSqr[index+1] = surfDistSqr[i];
112  }
113  }
114  }
115 }
116 
117 
118 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
119 
120 // Find any intersection
122 (
123  const PtrList<searchableSurface>& allSurfaces,
124  const labelList& surfacesToTest,
125  const pointField& start,
126  const pointField& end,
127  labelList& hitSurfaces,
128  List<pointIndexHit>& hitInfo
129 )
130 {
131  hitSurfaces.setSize(start.size());
132  hitSurfaces = -1;
133  hitInfo.setSize(start.size());
134 
135  // Work arrays
136  labelList hitMap(identity(start.size()));
137  pointField p0(start);
138  pointField p1(end);
139  List<pointIndexHit> intersectInfo(start.size());
140 
141  forAll(surfacesToTest, testI)
142  {
143  // Do synchronised call to all surfaces.
144  allSurfaces[surfacesToTest[testI]].findLineAny(p0, p1, intersectInfo);
145 
146  // Copy all hits into arguments, continue with misses
147  label newI = 0;
148  forAll(intersectInfo, i)
149  {
150  if (intersectInfo[i].hit())
151  {
152  hitInfo[hitMap[i]] = intersectInfo[i];
153  hitSurfaces[hitMap[i]] = testI;
154  }
155  else
156  {
157  if (i != newI)
158  {
159  hitMap[newI] = hitMap[i];
160  p0[newI] = p0[i];
161  p1[newI] = p1[i];
162  }
163  newI++;
164  }
165  }
166 
167  // All done? Note that this decision should be synchronised
168  if (newI == 0)
169  {
170  break;
171  }
172 
173  // Trim and continue
174  hitMap.setSize(newI);
175  p0.setSize(newI);
176  p1.setSize(newI);
177  intersectInfo.setSize(newI);
178  }
179 }
180 
181 
183 (
184  const PtrList<searchableSurface>& allSurfaces,
185  const labelList& surfacesToTest,
186  const pointField& start,
187  const pointField& end,
188  labelListList& hitSurfaces,
189  List<List<pointIndexHit>>& hitInfo
190 )
191 {
192  // Note: maybe move the single-surface all intersections test into
193  // searchable surface? Some of the tolerance issues might be
194  // lessened.
195 
196  // 2. Currently calling searchableSurface::findLine with start==end
197  // is expected to find no intersection. Problem if it does.
198 
199  hitSurfaces.setSize(start.size());
200  hitInfo.setSize(start.size());
201 
202  if (surfacesToTest.empty())
203  {
204  return;
205  }
206 
207  // Test first surface
208  allSurfaces[surfacesToTest[0]].findLineAll(start, end, hitInfo);
209 
210  // Set hitSurfaces and distance
211  List<scalarList> hitDistSqr(hitInfo.size());
212  forAll(hitInfo, pointi)
213  {
214  const List<pointIndexHit>& pHits = hitInfo[pointi];
215 
216  labelList& pSurfaces = hitSurfaces[pointi];
217  pSurfaces.setSize(pHits.size());
218  pSurfaces = 0;
219 
220  scalarList& pDistSqr = hitDistSqr[pointi];
221  pDistSqr.setSize(pHits.size());
222  forAll(pHits, i)
223  {
224  pDistSqr[i] = pHits[i].hitPoint().distSqr(start[pointi]);
225  }
226  }
227 
228 
229  if (surfacesToTest.size() > 1)
230  {
231  // Test the other surfaces and merge (according to distance from start).
232  for (label testI = 1; testI < surfacesToTest.size(); testI++)
233  {
234  List<List<pointIndexHit>> surfHits;
235  allSurfaces[surfacesToTest[testI]].findLineAll
236  (
237  start,
238  end,
239  surfHits
240  );
241 
242  forAll(surfHits, pointi)
243  {
244  mergeHits
245  (
246  start[pointi], // Current segment
247 
248  testI, // Surface and its hits
249  surfHits[pointi],
250 
251  hitSurfaces[pointi], // Merge into overall hit info
252  hitInfo[pointi],
253  hitDistSqr[pointi]
254  );
255  }
256  }
257  }
258 }
259 
260 
262 (
263  const PtrList<searchableSurface>& allSurfaces,
264  const labelList& surfacesToTest,
265  const pointField& start,
266  const pointField& end,
267  labelList& surface1,
268  List<pointIndexHit>& hit1,
269  labelList& surface2,
270  List<pointIndexHit>& hit2
271 )
272 {
273  // 1. intersection from start to end
274  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
275 
276  // Initialize arguments
277  surface1.setSize(start.size());
278  surface1 = -1;
279  hit1.setSize(start.size());
280 
281  // Current end of segment to test.
282  pointField nearest(end);
283  // Work array
284  List<pointIndexHit> nearestInfo(start.size());
285 
286  forAll(surfacesToTest, testI)
287  {
288  // See if any intersection between start and current nearest
289  allSurfaces[surfacesToTest[testI]].findLine
290  (
291  start,
292  nearest,
293  nearestInfo
294  );
295 
296  forAll(nearestInfo, pointi)
297  {
298  if (nearestInfo[pointi].hit())
299  {
300  hit1[pointi] = nearestInfo[pointi];
301  surface1[pointi] = testI;
302  nearest[pointi] = hit1[pointi].point();
303  }
304  }
305  }
306 
307 
308  // 2. intersection from end to last intersection
309  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
310 
311  // Find the nearest intersection from end to start. Note that we
312  // initialize to the first intersection (if any).
313  surface2 = surface1;
314  hit2 = hit1;
315 
316  // Set current end of segment to test.
317  forAll(nearest, pointi)
318  {
319  if (hit1[pointi].hit())
320  {
321  nearest[pointi] = hit1[pointi].point();
322  }
323  else
324  {
325  // Disable testing by setting to end.
326  nearest[pointi] = end[pointi];
327  }
328  }
329 
330  forAll(surfacesToTest, testI)
331  {
332  // See if any intersection between end and current nearest
333  allSurfaces[surfacesToTest[testI]].findLine(end, nearest, nearestInfo);
334 
335  forAll(nearestInfo, pointi)
336  {
337  if (nearestInfo[pointi].hit())
338  {
339  hit2[pointi] = nearestInfo[pointi];
340  surface2[pointi] = testI;
341  nearest[pointi] = hit2[pointi].point();
342  }
343  }
344  }
345 }
346 
347 
349 (
350  const PtrList<searchableSurface>& allSurfaces,
351  const labelList& surfacesToTest,
352  const pointField& samples,
353  const scalarField& nearestDistSqr,
354  labelList& nearestSurfaces,
355  List<pointIndexHit>& nearestInfo
356 )
357 {
358  // Find nearest. Return -1 or nearest point
359 
360  if (samples.size() != nearestDistSqr.size())
361  {
362  FatalErrorInFunction << "Inconsistent sizes. samples:" << samples.size()
363  << " search-radius:" << nearestDistSqr.size()
364  << exit(FatalError);
365  }
366 
367  // Initialise
368  nearestSurfaces.setSize(samples.size());
369  nearestSurfaces = -1;
370  nearestInfo.setSize(samples.size());
371 
372  // Work arrays
373  scalarField minDistSqr(nearestDistSqr);
374  List<pointIndexHit> hitInfo(samples.size());
375 
376  forAll(surfacesToTest, testI)
377  {
378  allSurfaces[surfacesToTest[testI]].findNearest
379  (
380  samples,
381  minDistSqr,
382  hitInfo
383  );
384 
385  // Update minDistSqr and arguments
386  forAll(hitInfo, pointi)
387  {
388  if (hitInfo[pointi].hit())
389  {
390  minDistSqr[pointi] =
391  hitInfo[pointi].point().distSqr(samples[pointi]);
392 
393  nearestInfo[pointi] = hitInfo[pointi];
394  nearestSurfaces[pointi] = testI;
395  }
396  }
397  }
398 }
399 
400 
402 (
403  const PtrList<searchableSurface>& allSurfaces,
404  const labelList& surfacesToTest,
405  const labelListList& regionIndices,
406 
407  const pointField& samples,
408  const scalarField& nearestDistSqr,
409 
410  labelList& nearestSurfaces,
411  List<pointIndexHit>& nearestInfo
412 )
413 {
414  // Find nearest. Return -1 or nearest point
415 
416  if (samples.size() != nearestDistSqr.size())
417  {
418  FatalErrorInFunction << "Inconsistent sizes. samples:" << samples.size()
419  << " search-radius:" << nearestDistSqr.size()
420  << exit(FatalError);
421  }
422 
423 
424  if (regionIndices.empty())
425  {
426  findNearest
427  (
428  allSurfaces,
429  surfacesToTest,
430  samples,
431  nearestDistSqr,
432  nearestSurfaces,
433  nearestInfo
434  );
435  }
436 
437  // Initialise
438  nearestSurfaces.setSize(samples.size());
439  nearestSurfaces = -1;
440  nearestInfo.setSize(samples.size());
441 
442  // Work arrays
443  scalarField minDistSqr(nearestDistSqr);
444  List<pointIndexHit> hitInfo(samples.size());
445 
446  forAll(surfacesToTest, testI)
447  {
448  allSurfaces[surfacesToTest[testI]].findNearest
449  (
450  samples,
451  minDistSqr,
452  regionIndices[testI],
453  hitInfo
454  );
455 
456  // Update minDistSqr and arguments
457  forAll(hitInfo, pointi)
458  {
459  if (hitInfo[pointi].hit())
460  {
461  minDistSqr[pointi] =
462  hitInfo[pointi].point().distSqr(samples[pointi]);
463 
464  nearestInfo[pointi] = hitInfo[pointi];
465  nearestSurfaces[pointi] = testI;
466  }
467  }
468  }
469 }
470 
471 
473 (
474  const PtrList<searchableSurface>& allSurfaces,
475  const labelList& surfacesToTest,
476  const pointField& start,
477  const scalarField& distSqr,
478  pointField& near,
479  List<pointConstraint>& constraint,
480  const label nIter
481 )
482 {
483  // Multi-surface findNearest
484 
485 
486  if (start.size() != distSqr.size())
487  {
488  FatalErrorInFunction << "Inconsistent sizes. samples:" << start.size()
489  << " search-radius:" << distSqr.size()
490  << exit(FatalError);
491  }
492 
493 
494  vectorField normal;
495  List<pointIndexHit> info;
496 
497  allSurfaces[surfacesToTest[0]].findNearest(start, distSqr, info);
498  allSurfaces[surfacesToTest[0]].getNormal(info, normal);
499 
500  // Extract useful info from initial start point
501  near = start;
502  forAll(info, i)
503  {
504  if (info[i].hit())
505  {
506  near[i] = info[i].point();
507  }
508  }
509 
510  // Store normal as constraint
511  constraint.setSize(near.size());
512  constraint = pointConstraint();
513  forAll(constraint, i)
514  {
515  if (info[i].hit())
516  {
517  constraint[i].applyConstraint(normal[i]);
518  }
519  }
520 
521  if (surfacesToTest.size() >= 2)
522  {
523  // Work space
524  //pointField near1;
525  vectorField normal1;
526 
527  label surfi = 1;
528  for (label iter = 0; iter < nIter; iter++)
529  {
530  // Find nearest on next surface
531  const searchableSurface& s = allSurfaces[surfacesToTest[surfi]];
532 
533  // Update: info, normal1
534  s.findNearest(near, distSqr, info);
535  s.getNormal(info, normal1);
536 
537  // Move to intersection of
538  // - previous surface(s) : near+normal
539  // - current surface : info+normal1
540  forAll(near, i)
541  {
542  if (info[i].hit())
543  {
544  if (normal[i] != vector::zero)
545  {
546  // Have previous hit. Find intersection
547  if (mag(normal[i]&normal1[i]) < 1.0-1e-6)
548  {
549  plane pl0(near[i], normal[i], false);
550  plane pl1(info[i].point(), normal1[i], false);
551 
552  plane::ray r(pl0.planeIntersect(pl1));
553  vector n = r.dir() / mag(r.dir());
554 
555  // Calculate vector to move onto intersection line
556  vector d(r.refPoint()-near[i]);
557  d.removeCollinear(n);
558 
559  // Trim the max distance
560  scalar magD = mag(d);
561  if (magD > SMALL)
562  {
563  scalar maxDist = Foam::sqrt(distSqr[i]);
564  if (magD > maxDist)
565  {
566  // Clip
567  d /= magD;
568  d *= maxDist;
569  }
570 
571  near[i] += d;
572  normal[i] = normal1[i];
573  constraint[i].applyConstraint(normal1[i]);
574  }
575  }
576  }
577  else
578  {
579  // First hit
580  near[i] = info[i].point();
581  normal[i] = normal1[i];
582  constraint[i].applyConstraint(normal1[i]);
583  }
584  }
585  }
586 
587  // Step to next surface
588  surfi = surfacesToTest.fcIndex(surfi);
589  }
590  }
591 }
592 
593 
595 (
596  const PtrList<searchableSurface>& allSurfaces,
597  const labelList& surfacesToTest,
598  const pointField& samples,
599  const scalarField& nearestDistSqr,
600  const volumeType illegalHandling,
601  labelList& nearestSurfaces,
603 )
604 {
605  // Initialise
606  distance.setSize(samples.size());
607  distance = -GREAT;
608 
609  // Find nearest
610  List<pointIndexHit> nearestInfo;
611  findNearest
612  (
613  allSurfaces,
614  surfacesToTest,
615  samples,
616  nearestDistSqr,
617  nearestSurfaces,
618  nearestInfo
619  );
620 
621  // Determine sign of nearest. Sort by surface to do this.
622  DynamicField<point> surfPoints(samples.size());
623  DynamicList<label> surfIndices(samples.size());
624 
625  forAll(surfacesToTest, testI)
626  {
627  // Extract samples on this surface
628  surfPoints.clear();
629  surfIndices.clear();
630  forAll(nearestSurfaces, i)
631  {
632  if (nearestSurfaces[i] == testI)
633  {
634  surfPoints.append(samples[i]);
635  surfIndices.append(i);
636  }
637  }
638 
639  // Calculate sideness of these surface points
640  List<volumeType> volType;
641  allSurfaces[surfacesToTest[testI]].getVolumeType(surfPoints, volType);
642 
643  // Push back to original
644  forAll(volType, i)
645  {
646  label pointi = surfIndices[i];
647  scalar dist = samples[pointi].dist(nearestInfo[pointi].hitPoint());
648 
649  volumeType vT = volType[i];
650 
651  if (vT == volumeType::OUTSIDE)
652  {
653  distance[pointi] = dist;
654  }
655  else if (vT == volumeType::INSIDE)
656  {
657  distance[i] = -dist;
658  }
659  else
660  {
661  switch (illegalHandling)
662  {
663  case volumeType::OUTSIDE:
664  {
665  distance[pointi] = dist;
666  break;
667  }
668  case volumeType::INSIDE:
669  {
670  distance[pointi] = -dist;
671  break;
672  }
673  default:
674  {
676  << "getVolumeType failure,"
677  << " neither INSIDE or OUTSIDE."
678  << " point:" << surfPoints[i]
679  << " surface:"
680  << allSurfaces[surfacesToTest[testI]].name()
681  << " volType:" << vT.str()
682  << exit(FatalError);
683  break;
684  }
685  }
686  }
687  }
688  }
689 }
690 
691 
693 (
694  const PtrList<searchableSurface>& allSurfaces,
695  const labelUList& surfacesToTest
696 )
697 {
698  boundBox bb;
699 
700  for (const label surfi : surfacesToTest)
701  {
702  bb.add(allSurfaces[surfi].bounds());
703  }
704 
705  return bb;
706 }
707 
708 
709 // ************************************************************************* //
List< scalar > scalarList
List of scalar.
Definition: scalarList.H:32
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
label findLower(const ListType &input, const T &val, const label start, const ComparePredicate &comp)
Binary search to find the index of the last element in a sorted list that is less than value...
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:598
static void findNearest(const PtrList< searchableSurface > &, const labelList &surfacesToTest, const pointField &, const scalarField &nearestDistSqr, labelList &surfaces, List< pointIndexHit > &)
Find nearest. Return -1 (and a miss()) or surface and nearest.
scalarField samples(nIntervals, Zero)
dimensionedScalar sqrt(const dimensionedScalar &ds)
scalar distance(const vector &p1, const vector &p2)
Definition: curveTools.C:12
A bounding box defined in terms of min/max extrema points.
Definition: boundBox.H:63
static void findAllIntersections(const PtrList< searchableSurface > &, const labelList &surfacesToTest, const pointField &start, const pointField &end, labelListList &surfaces, List< List< pointIndexHit >> &surfaceHits)
Find all intersections in order from start to end. Returns for.
List< labelList > labelListList
List of labelList.
Definition: labelList.H:38
UList< label > labelUList
A UList of labels.
Definition: UList.H:78
static void signedDistance(const PtrList< searchableSurface > &allSurfaces, const labelList &surfacesToTest, const pointField &samples, const scalarField &nearestDistSqr, const volumeType illegalHandling, labelList &nearestSurfaces, scalarField &distance)
Find signed distance to nearest surface. Outside is positive.
Various functions to operate on Lists.
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
void add(const boundBox &bb)
Extend to include the second box.
Definition: boundBoxI.H:323
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:38
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
void setSize(const label n)
Alias for resize()
Definition: List.H:316
static void findNearestIntersection(const PtrList< searchableSurface > &allSurfaces, const labelList &surfacesToTest, const pointField &start, const pointField &end, labelList &surface1, List< pointIndexHit > &hit1, labelList &surface2, List< pointIndexHit > &hit2)
Find intersections of edge nearest to both endpoints.
labelList identity(const label len, label start=0)
Return an identity map of the given length with (map[i] == i), works like std::iota() but returning a...
Definition: labelLists.C:44
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
Vector< scalar > vector
Definition: vector.H:57
A location inside the volume.
Definition: volumeType.H:65
static void findAnyIntersection(const PtrList< searchableSurface > &, const labelList &surfacesToTest, const pointField &start, const pointField &end, labelList &surfaces, List< pointIndexHit > &)
Find any intersection. Return hit point information and.
A location outside the volume.
Definition: volumeType.H:66
constexpr auto end(C &c) -> decltype(c.end())
Return iterator to the end of the container c.
Definition: stdFoam.H:201
defineTypeNameAndDebug(combustionModel, 0)
vector point
Point is a vector.
Definition: point.H:37
label n
Field< vector > vectorField
Specialisation of Field<T> for vector.
List< label > labelList
A List of labels.
Definition: List.H:62
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
Vector< Cmpt > & removeCollinear(const Vector< Cmpt > &unitVec)
Inplace removal of components that are collinear to the given unit vector.
Definition: VectorI.H:136
const volScalarField & p0
Definition: EEqn.H:36
Namespace for OpenFOAM.
static boundBox bounds(const PtrList< searchableSurface > &allSurfaces, const labelUList &surfacesToTest)
Find the boundBox of the selected surfaces.