searchableCone.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) 2015-2022 OpenCFD Ltd.
9 -------------------------------------------------------------------------------
10 License
11  This file is part of OpenFOAM.
12 
13  OpenFOAM is free software: you can redistribute it and/or modify it
14  under the terms of the GNU General Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25 
26 \*---------------------------------------------------------------------------*/
27 
28 #include "searchableCone.H"
30 
31 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
32 
33 namespace Foam
34 {
35  defineTypeNameAndDebug(searchableCone, 0);
37  (
38  searchableSurface,
39  searchableCone,
40  dict
41  );
43  (
44  searchableSurface,
45  searchableCone,
46  dict,
47  cone
48  );
49 }
50 
51 
52 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
53 
55 {
56  return tmp<pointField>::New(1, 0.5*(point1_ + point2_));
57 }
58 
59 
61 (
62  pointField& centres,
63  scalarField& radiusSqr
64 ) const
65 {
66  centres.setSize(1);
67  centres[0] = 0.5*(point1_ + point2_);
68 
69  radiusSqr.setSize(1);
70  if (radius1_ > radius2_)
71  {
72  radiusSqr[0] = Foam::magSqr(point1_-centres[0]) + Foam::sqr(radius1_);
73  }
74  else
75  {
76  radiusSqr[0] = Foam::magSqr(point2_-centres[0]) + Foam::sqr(radius2_);
77  }
78 
79  // Add a bit to make sure all points are tested inside
80  radiusSqr += Foam::sqr(SMALL);
81 }
82 
83 
85 {
86  auto tpts = tmp<pointField>::New(2);
87  auto& pts = tpts.ref();
88 
89  pts[0] = point1_;
90  pts[1] = point2_;
91 
92  return tpts;
93 }
94 
95 
96 void Foam::searchableCone::findNearestAndNormal
97 (
98  const point& sample,
99  const scalar nearestDistSqr,
100  pointIndexHit& info,
101  vector& nearNormal
102 ) const
103 {
104  vector v(sample - point1_);
105 
106  // Decompose sample-point1 into normal and parallel component
107  const scalar parallel = (v & unitDir_);
108 
109  // Remove the parallel component and normalise
110  v -= parallel*unitDir_;
111 
112  const scalar magV = mag(v);
113  v.normalise();
114 
115  // Nearest and normal on disk at point1
116  point disk1Point(point1_ + clamp(magV, innerRadius1_, radius1_)*v);
117  vector disk1Normal(-unitDir_);
118 
119  // Nearest and normal on disk at point2
120  point disk2Point(point2_ + clamp(magV, innerRadius2_, radius2_)*v);
121  vector disk2Normal(unitDir_);
122 
123  // Nearest and normal on cone. Initialise to far-away point so if not
124  // set it picks one of the disk points
125  point nearCone(point::uniform(GREAT));
126  vector normalCone(1, 0, 0);
127 
128  // Nearest and normal on inner cone. Initialise to far-away point
129  point iCnearCone(point::uniform(GREAT));
130  vector iCnormalCone(1, 0, 0);
131 
132  point projPt1 = point1_+ radius1_*v;
133  point projPt2 = point2_+ radius2_*v;
134 
135  vector p1 = (projPt1 - point1_);
136  if (mag(p1) > ROOTVSMALL)
137  {
138  p1 /= mag(p1);
139 
140  // Find vector along the two end of cone
141  const vector b = normalised(projPt2 - projPt1);
142 
143  // Find the vector along sample pt and pt at one end of cone
144  vector a = (sample - projPt1);
145 
146  if (mag(a) <= ROOTVSMALL)
147  {
148  // Exception: sample on disk1. Redo with projPt2.
149  a = (sample - projPt2);
150 
151  // Find normal unitvector
152  nearCone = (a & b)*b + projPt2;
153 
154  vector b1 = (p1 & b)*b;
155  normalCone = normalised(p1 - b1);
156  }
157  else
158  {
159  // Find nearest point on cone surface
160  nearCone = (a & b)*b + projPt1;
161 
162  // Find projection along surface of cone
163  vector b1 = (p1 & b)*b;
164  normalCone = normalised(p1 - b1);
165  }
166 
167  if (innerRadius1_ > 0 || innerRadius2_ > 0)
168  {
169  // Same for inner radius
170  point iCprojPt1 = point1_+ innerRadius1_*v;
171  point iCprojPt2 = point2_+ innerRadius2_*v;
172 
173  const vector iCp1 = normalised(iCprojPt1 - point1_);
174 
175  // Find vector along the two end of cone
176  const vector iCb = normalised(iCprojPt2 - iCprojPt1);
177 
178 
179  // Find the vector along sample pt and pt at one end of conde
180  vector iCa(sample - iCprojPt1);
181 
182  if (mag(iCa) <= ROOTVSMALL)
183  {
184  iCa = (sample - iCprojPt2);
185 
186  // Find normal unitvector
187  iCnearCone = (iCa & iCb)*iCb+iCprojPt2;
188 
189  vector b1 = (iCp1 & iCb)*iCb;
190  iCnormalCone = normalised(iCp1 - b1);
191  }
192  else
193  {
194  // Find nearest point on cone surface
195  iCnearCone = (iCa & iCb)*iCb+iCprojPt1;
196 
197  // Find projection along surface of cone
198  vector b1 = (iCp1 & iCb)*iCb;
199  iCnormalCone = normalised(iCp1 - b1);
200  }
201  }
202  }
203 
204 
205  // Select nearest out of the 4 points (outer cone, disk1, disk2, inner
206  // cone)
207 
208  FixedList<scalar, 4> dist;
209  dist[0] = sample.distSqr(nearCone);
210  dist[1] = sample.distSqr(disk1Point);
211  dist[2] = sample.distSqr(disk2Point);
212  dist[3] = sample.distSqr(iCnearCone);
213 
214  const label minI = findMin(dist);
215 
216 
217  // Snap the point to the corresponding surface
218 
219  if (minI == 0) // Outer cone
220  {
221  // Closest to (infinite) outer cone. See if needs clipping to end disks
222 
223  {
224  vector v1(nearCone-point1_);
225  scalar para = (v1 & unitDir_);
226  // Remove the parallel component and normalise
227  v1 -= para*unitDir_;
228  const scalar magV1 = mag(v1);
229  v1 = v1/magV1;
230 
231  if (para < 0.0 && magV1 >= radius1_)
232  {
233  // Near point 1. Set point to intersection of disk and cone.
234  // Keep normal from cone.
235  nearCone = disk1Point;
236  }
237  else if (para < 0.0 && magV1 < radius1_)
238  {
239  // On disk1
240  nearCone = disk1Point;
241  normalCone = disk1Normal;
242  }
243  else if (para > magDir_ && magV1 >= radius2_)
244  {
245  // Near point 2. Set point to intersection of disk and cone.
246  // Keep normal from cone.
247  nearCone = disk2Point;
248  }
249  else if (para > magDir_ && magV1 < radius2_)
250  {
251  // On disk2
252  nearCone = disk2Point;
253  normalCone = disk2Normal;
254  }
255  }
256  info.setPoint(nearCone);
257  nearNormal = normalCone;
258  }
259  else if (minI == 1) // Near to disk1
260  {
261  info.setPoint(disk1Point);
262  nearNormal = disk1Normal;
263  }
264  else if (minI == 2) // Near to disk2
265  {
266  info.setPoint(disk2Point);
267  nearNormal = disk2Normal;
268  }
269  else // Near to inner cone
270  {
271  {
272  vector v1(iCnearCone-point1_);
273  scalar para = (v1 & unitDir_);
274  // Remove the parallel component and normalise
275  v1 -= para*unitDir_;
276 
277  const scalar magV1 = mag(v1);
278  v1 = v1/magV1;
279 
280  if (para < 0.0 && magV1 >= innerRadius1_)
281  {
282  iCnearCone = disk1Point;
283  }
284  else if (para < 0.0 && magV1 < innerRadius1_)
285  {
286  iCnearCone = disk1Point;
287  iCnormalCone = disk1Normal;
288  }
289  else if (para > magDir_ && magV1 >= innerRadius2_)
290  {
291  iCnearCone = disk2Point;
292  }
293  else if (para > magDir_ && magV1 < innerRadius2_)
294  {
295  iCnearCone = disk2Point;
296  iCnormalCone = disk2Normal;
297  }
298  }
299  info.setPoint(iCnearCone);
300  nearNormal = iCnormalCone;
301  }
302 
303 
304  if (info.point().distSqr(sample) < nearestDistSqr)
305  {
306  info.setHit();
307  info.setIndex(0);
308  }
309 }
310 
311 
312 Foam::scalar Foam::searchableCone::radius2
313 (
314  const searchableCone& cone,
315  const point& pt
316 )
317 {
318  const vector x = (pt-cone.point1_) ^ cone.unitDir_;
319  return x&x;
320 }
321 
322 
323 // From mrl.nyu.edu/~dzorin/rend05/lecture2.pdf,
324 // Ray Tracing II, Infinite cone ray intersection.
325 void Foam::searchableCone::findLineAll
326 (
327  const searchableCone& cone,
328  const scalar innerRadius1,
329  const scalar innerRadius2,
330  const point& start,
331  const point& end,
332  pointIndexHit& near,
333  pointIndexHit& far
334 ) const
335 {
336  near.setMiss();
337  far.setMiss();
338 
339  vector point1Start(start-cone.point1_);
340  vector point2Start(start-cone.point2_);
341  vector point1End(end-cone.point1_);
342 
343  // Quick rejection of complete vector outside endcaps
344  scalar s1 = point1Start & (cone.unitDir_);
345  scalar s2 = point1End & (cone.unitDir_);
346 
347  if ((s1 < 0.0 && s2 < 0.0) || (s1 > cone.magDir_ && s2 > cone.magDir_))
348  {
349  return;
350  }
351 
352  // Line as P = start+t*V where V is unit vector and t=[0..mag(end-start)]
353  vector V(end-start);
354  scalar magV = mag(V);
355  if (magV < ROOTVSMALL)
356  {
357  return;
358  }
359  V /= magV;
360 
361 
362  // We now get the nearest intersections to start. This can either be
363  // the intersection with the end plane or with the cylinder side.
364 
365  // Get the two points (expressed in t) on the end planes. This is to
366  // clip any cylinder intersection against.
367  scalar tPoint1;
368  scalar tPoint2;
369 
370  // Maintain the two intersections with the endcaps
371  scalar tNear = VGREAT;
372  scalar tFar = VGREAT;
373 
374  scalar radius_sec = cone.radius1_;
375 
376  {
377  // Find dot product: mag(s)>VSMALL suggest that it is greater
378  scalar s = (V & unitDir_);
379  if (mag(s) > VSMALL)
380  {
381  tPoint1 = -s1/s;
382  tPoint2 = -(point2Start&(cone.unitDir_))/s;
383 
384  if (tPoint2 < tPoint1)
385  {
386  std::swap(tPoint1, tPoint2);
387  }
388  if (tPoint1 > magV || tPoint2 < 0)
389  {
390  return;
391  }
392  // See if the points on the endcaps are actually inside the cylinder
393  if (tPoint1 >= 0 && tPoint1 <= magV)
394  {
395  scalar r2 = radius2(cone, start+tPoint1*V);
396  vector p1 = (start+tPoint1*V-point1_);
397  vector p2 = (start+tPoint1*V-point2_);
398  radius_sec = cone.radius1_;
399  scalar inC_radius_sec = innerRadius1_;
400 
401  if (mag(p2&(cone.unitDir_)) < mag(p1&(cone.unitDir_)))
402  {
403  radius_sec = cone.radius2_;
404  inC_radius_sec = innerRadius2_;
405  }
406 
407  if (r2 <= sqr(radius_sec) && r2 >= sqr(inC_radius_sec))
408  {
409  tNear = tPoint1;
410  }
411  }
412  if (tPoint2 >= 0 && tPoint2 <= magV)
413  {
414  // Decompose sample-point1 into normal and parallel component
415  vector p1 = (start+tPoint2*V-cone.point1_);
416  vector p2 = (start+tPoint2*V-cone.point2_);
417  radius_sec = cone.radius1_;
418  scalar inC_radius_sec = innerRadius1_;
419  if (mag(p2&(cone.unitDir_)) < mag(p1&(cone.unitDir_)))
420  {
421  radius_sec = cone.radius2_;
422  inC_radius_sec = innerRadius2_;
423  }
424  scalar r2 = radius2(cone, start+tPoint2*V);
425  if (r2 <= sqr(radius_sec) && r2 >= sqr(inC_radius_sec))
426  {
427  // Check if already have a near hit from point1
428  if (tNear <= 1)
429  {
430  tFar = tPoint2;
431  }
432  else
433  {
434  tNear = tPoint2;
435  }
436  }
437  }
438  }
439  else
440  {
441  // Vector perpendicular to cylinder. Check for outside already done
442  // above so just set tpoint to allow all.
443  tPoint1 = -VGREAT;
444  tPoint2 = VGREAT;
445  }
446  }
447 
448 
449  // Second order equation of the form a*t^2 + b*t + c
450  scalar a, b, c;
451 
452  scalar deltaRadius = cone.radius2_-cone.radius1_;
453  if (mag(deltaRadius) <= ROOTVSMALL)
454  {
455  vector point1Start(start-cone.point1_);
456  const vector x = point1Start ^ cone.unitDir_;
457  const vector y = V ^ cone.unitDir_;
458  const scalar d = sqr(0.5*(cone.radius1_ + cone.radius2_));
459 
460  a = (y&y);
461  b = 2*(x&y);
462  c = (x&x)-d;
463  }
464  else
465  {
466  vector va = cone.unitDir_;
467  vector v1 = normalised(end-start);
468  scalar p = (va&v1);
469  vector a1 = (v1-p*va);
470 
471  // Determine the end point of the cone
472  point pa =
473  cone.unitDir_*cone.radius1_*mag(cone.point2_-cone.point1_)
474  /(-deltaRadius)
475  +cone.point1_;
476 
477  scalar l2 = sqr(deltaRadius)+sqr(cone.magDir_);
478  scalar sqrCosAlpha = sqr(cone.magDir_)/l2;
479  scalar sqrSinAlpha = sqr(deltaRadius)/l2;
480 
481 
482  vector delP(start-pa);
483  vector p1 = (delP-(delP&va)*va);
484 
485  a = sqrCosAlpha*((v1-p*va)&(v1-p*va))-sqrSinAlpha*p*p;
486  b =
487  2.0*sqrCosAlpha*(a1&p1)
488  -2.0*sqrSinAlpha*(v1&va)*(delP&va);
489  c =
490  sqrCosAlpha
491  *((delP-(delP&va)*va)&(delP-(delP&va)*va))
492  -sqrSinAlpha*sqr(delP&va);
493  }
494 
495  const scalar disc = b*b-4.0*a*c;
496 
497  scalar t1 = -VGREAT;
498  scalar t2 = VGREAT;
499 
500  if (disc < 0)
501  {
502  // Fully outside
503  return;
504  }
505  else if (disc < ROOTVSMALL)
506  {
507  // Single solution
508  if (mag(a) > ROOTVSMALL)
509  {
510  t1 = -b/(2.0*a);
511 
512  if (t1 >= 0.0 && t1 <= magV && t1 >= tPoint1 && t1 <= tPoint2)
513  {
514  // Valid. Insert sorted.
515  if (t1 < tNear)
516  {
517  tFar = tNear;
518  tNear = t1;
519  }
520  else if (t1 < tFar)
521  {
522  tFar = t1;
523  }
524  }
525  else
526  {
527  return;
528  }
529  }
530  else
531  {
532  // Aligned with axis. Check if outside radius
533  if (c > 0.0)
534  {
535  return;
536  }
537  }
538  }
539  else
540  {
541  if (mag(a) > ROOTVSMALL)
542  {
543  scalar sqrtDisc = sqrt(disc);
544 
545  t1 = (-b - sqrtDisc)/(2.0*a);
546  t2 = (-b + sqrtDisc)/(2.0*a);
547  if (t2 < t1)
548  {
549  std::swap(t1, t2);
550  }
551 
552  if (t1 >= 0.0 && t1 <= magV && t1 >= tPoint1 && t1 <= tPoint2)
553  {
554  // Valid. Insert sorted.
555  if (t1 < tNear)
556  {
557  tFar = tNear;
558  tNear = t1;
559  }
560  else if (t1 < tFar)
561  {
562  tFar = t1;
563  }
564  }
565  if (t2>=0 && t2 <= magV && t2 >= tPoint1 && t2 <= tPoint2)
566  {
567  // Valid. Insert sorted.
568  if (t2 < tNear)
569  {
570  tFar = tNear;
571  tNear = t2;
572  }
573  else if (t2 < tFar)
574  {
575  tFar = t2;
576  }
577  }
578  }
579  else
580  {
581  // Aligned with axis. Check if outside radius
582  if (c > 0.0)
583  {
584  return;
585  }
586  }
587  }
588 
589  // Check tNear, tFar
590  if (tNear>=0 && tNear <= magV)
591  {
592  near.hitPoint(start+tNear*V);
593  near.setIndex(0);
594  if (tFar <= magV)
595  {
596  far.hitPoint(start+tFar*V);
597  far.setIndex(0);
598  }
599  }
600  else if (tFar>=0 && tFar <= magV)
601  {
602  near.hitPoint(start+tFar*V);
603  near.setIndex(0);
604  }
605 }
606 
607 
608 void Foam::searchableCone::insertHit
609 (
610  const point& start,
611  const point& end,
612  List<pointIndexHit>& info,
613  const pointIndexHit& hit
614 ) const
615 {
616  scalar smallDistSqr = SMALL*magSqr(end-start);
617 
618  scalar hitMagSqr = hit.hitPoint().distSqr(start);
619 
620  forAll(info, i)
621  {
622  scalar d2 = info[i].hitPoint().distSqr(start);
623 
624  if (d2 > hitMagSqr+smallDistSqr)
625  {
626  // Insert at i.
627  label sz = info.size();
628  info.setSize(sz+1);
629  for (label j = sz; j > i; --j)
630  {
631  info[j] = info[j-1];
632  }
633  info[i] = hit;
634  return;
635  }
636  else if (d2 > hitMagSqr-smallDistSqr)
637  {
638  // hit is same point as info[i].
639  return;
640  }
641  }
642  // Append
643  label sz = info.size();
644  info.setSize(sz+1);
645  info[sz] = hit;
646 }
647 
648 
649 Foam::boundBox Foam::searchableCone::calcBounds() const
650 {
651  // Adapted from
652  // http://www.gamedev.net/community/forums
653  // /topic.asp?topic_id=338522&forum_id=20&gforum_id=0
654 
655  // Let cylinder have end points A,B and radius r,
656 
657  // Bounds in direction X (same for Y and Z) can be found as:
658  // Let A.X<B.X (otherwise swap points)
659  // Good approximate lowest bound is A.X-r and highest is B.X+r (precise for
660  // capsule). At worst, in one direction it can be larger than needed by 2*r.
661 
662  // Accurate bounds for cylinder is
663  // A.X-kx*r, B.X+kx*r
664  // where
665  // kx=sqrt(((A.Y-B.Y)^2+(A.Z-B.Z)^2)/((A.X-B.X)^2+(A.Y-B.Y)^2+(A.Z-B.Z)^2))
666 
667  // similar thing for Y and Z
668  // (i.e.
669  // ky=sqrt(((A.X-B.X)^2+(A.Z-B.Z)^2)/((A.X-B.X)^2+(A.Y-B.Y)^2+(A.Z-B.Z)^2))
670  // kz=sqrt(((A.X-B.X)^2+(A.Y-B.Y)^2)/((A.X-B.X)^2+(A.Y-B.Y)^2+(A.Z-B.Z)^2))
671  // )
672 
673  // How derived: geometric reasoning. Bounds of cylinder is same as for 2
674  // circles centered on A and B. This sqrt thingy gives sine of angle between
675  // axis and direction, used to find projection of radius.
676 
677  vector kr
678  (
679  sqrt(sqr(unitDir_.y()) + sqr(unitDir_.z())),
680  sqrt(sqr(unitDir_.x()) + sqr(unitDir_.z())),
681  sqrt(sqr(unitDir_.x()) + sqr(unitDir_.y()))
682  );
683 
684  if (radius2_ >= radius1_)
685  {
686  kr *= radius2_;
687  }
688  else
689  {
690  kr *= radius1_;
691  }
692 
693  point min = point1_ - kr;
694  point max = point1_ + kr;
695 
696  min = ::Foam::min(min, point2_ - kr);
697  max = ::Foam::max(max, point2_ + kr);
698 
699  return boundBox(min, max);
700 }
701 
702 
703 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
704 
705 Foam::searchableCone::searchableCone
706 (
707  const IOobject& io,
708  const point& point1,
709  const scalar radius1,
710  const scalar innerRadius1,
711  const point& point2,
712  const scalar radius2,
713  const scalar innerRadius2
714 )
715 :
717  point1_(point1),
718  radius1_(radius1),
719  innerRadius1_(innerRadius1),
720  point2_(point2),
721  radius2_(radius2),
722  innerRadius2_(innerRadius2),
723  magDir_(mag(point2_-point1_)),
724  unitDir_((point2_-point1_)/magDir_)
725 {
726  bounds() = calcBounds();
727 }
728 
729 
730 Foam::searchableCone::searchableCone
731 (
732  const IOobject& io,
733  const dictionary& dict
734 )
735 :
737  point1_(dict.get<point>("point1")),
738  radius1_(dict.get<scalar>("radius1")),
739  innerRadius1_(dict.getOrDefault<scalar>("innerRadius1", 0)),
740  point2_(dict.get<point>("point2")),
741  radius2_(dict.get<scalar>("radius2")),
742  innerRadius2_(dict.getOrDefault<scalar>("innerRadius2", 0)),
743  magDir_(mag(point2_-point1_)),
744  unitDir_((point2_-point1_)/magDir_)
745 {
746  bounds() = calcBounds();
747 }
748 
749 
750 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
751 
753 {
754  if (regions_.empty())
755  {
756  regions_.setSize(1);
757  regions_[0] = "region0";
758  }
759  return regions_;
760 }
761 
762 
764 (
765  const pointField& samples,
766  const scalarField& nearestDistSqr,
767  List<pointIndexHit>& info
768 ) const
769 {
770  info.setSize(samples.size());
771 
772  forAll(samples, i)
773  {
774  vector normal;
775  findNearestAndNormal(samples[i], nearestDistSqr[i], info[i], normal);
776  }
777 }
778 
779 
781 (
782  const pointField& start,
783  const pointField& end,
784  List<pointIndexHit>& info
785 ) const
786 {
787  info.setSize(start.size());
788 
789  forAll(start, i)
790  {
791  // Pick nearest intersection. If none intersected take second one.
793  findLineAll
794  (
795  *this,
796  innerRadius1_,
797  innerRadius2_,
798  start[i],
799  end[i],
800  info[i],
801  b
802  );
803  if (!info[i].hit() && b.hit())
804  {
805  info[i] = b;
806  }
807  }
808 
809 
810  if (innerRadius1_ > 0.0 || innerRadius2_ > 0.0)
811  {
812  IOobject io(*this);
813  io.rename(name()+"Inner");
814  searchableCone innerCone
815  (
816  io,
817  point1_,
818  innerRadius1_,
819  0.0,
820  point2_,
821  innerRadius2_,
822  0.0
823  );
824 
825  forAll(info, i)
826  {
827  point newEnd;
828  if (info[i].hit())
829  {
830  newEnd = info[i].point();
831  }
832  else
833  {
834  newEnd = end[i];
835  }
836  pointIndexHit near;
837  pointIndexHit far;
838  findLineAll
839  (
840  innerCone,
841  innerRadius1_,
842  innerRadius2_,
843  start[i],
844  newEnd,
845  near,
846  far
847  );
848 
849  if (near.hit())
850  {
851  info[i] = near;
852  }
853  else if (far.hit())
854  {
855  info[i] = far;
856  }
857  }
858  }
859 }
860 
861 
863 (
864  const pointField& start,
865  const pointField& end,
866  List<pointIndexHit>& info
867 ) const
868 {
869  info.setSize(start.size());
870 
871  forAll(start, i)
872  {
873  // Discard far intersection
875  findLineAll
876  (
877  *this,
878  innerRadius1_,
879  innerRadius2_,
880  start[i],
881  end[i],
882  info[i],
883  b
884  );
885  if (!info[i].hit() && b.hit())
886  {
887  info[i] = b;
888  }
889  }
890  if (innerRadius1_ > 0.0 || innerRadius2_ > 0.0)
891  {
892  IOobject io(*this);
893  io.rename(name()+"Inner");
894  searchableCone cone
895  (
896  io,
897  point1_,
898  innerRadius1_,
899  0.0,
900  point2_,
901  innerRadius2_,
902  0.0
903  );
904 
905  forAll(info, i)
906  {
907  if (!info[i].hit())
908  {
910  findLineAll
911  (
912  cone,
913  innerRadius1_,
914  innerRadius2_,
915  start[i],
916  end[i],
917  info[i],
918  b
919  );
920  if (!info[i].hit() && b.hit())
921  {
922  info[i] = b;
923  }
924  }
925  }
926  }
927 }
928 
929 
930 void Foam::searchableCone::findLineAll
931 (
932  const pointField& start,
933  const pointField& end,
934  List<List<pointIndexHit>>& info
935 ) const
936 {
937  info.setSize(start.size());
938 
939  forAll(start, i)
940  {
941  pointIndexHit near, far;
942  findLineAll
943  (
944  *this,
945  innerRadius1_,
946  innerRadius2_,
947  start[i],
948  end[i],
949  near,
950  far
951  );
952 
953  if (near.hit())
954  {
955  if (far.hit())
956  {
957  info[i].setSize(2);
958  info[i][0] = near;
959  info[i][1] = far;
960  }
961  else
962  {
963  info[i].setSize(1);
964  info[i][0] = near;
965  }
966  }
967  else
968  {
969  if (far.hit())
970  {
971  info[i].setSize(1);
972  info[i][0] = far;
973  }
974  else
975  {
976  info[i].clear();
977  }
978  }
979  }
980 
981  if (innerRadius1_ > 0.0 || innerRadius2_ > 0.0)
982  {
983  IOobject io(*this);
984  io.rename(name()+"Inner");
985  searchableCone cone
986  (
987  io,
988  point1_,
989  innerRadius1_,
990  0.0,
991  point2_,
992  innerRadius2_,
993  0.0
994  );
995 
996  forAll(info, i)
997  {
998  pointIndexHit near;
999  pointIndexHit far;
1000  findLineAll
1001  (
1002  cone,
1003  innerRadius1_,
1004  innerRadius2_,
1005  start[i],
1006  end[i],
1007  near,
1008  far
1009  );
1010 
1011  if (near.hit())
1012  {
1013  insertHit(start[i], end[i], info[i], near);
1014  }
1015  if (far.hit())
1016  {
1017  insertHit(start[i], end[i], info[i], far);
1018  }
1019  }
1020  }
1021 }
1022 
1023 
1025 (
1026  const List<pointIndexHit>& info,
1027  labelList& region
1028 ) const
1030  region.setSize(info.size());
1031  region = 0;
1032 }
1033 
1034 
1036 (
1037  const List<pointIndexHit>& info,
1038  vectorField& normal
1039 ) const
1040 {
1041  normal.setSize(info.size());
1042  normal = Zero;
1043 
1044  forAll(info, i)
1045  {
1046  if (info[i].hit())
1047  {
1048  pointIndexHit nearInfo;
1049  findNearestAndNormal
1050  (
1051  info[i].point(),
1052  Foam::sqr(GREAT),
1053  nearInfo,
1054  normal[i]
1055  );
1056  }
1057  }
1058 }
1059 
1060 
1062 (
1063  const pointField& points,
1064  List<volumeType>& volType
1065 ) const
1066 {
1067  volType.setSize(points.size());
1068 
1069  forAll(points, pointi)
1070  {
1071  const point& pt = points[pointi];
1072 
1073  volType[pointi] = volumeType::OUTSIDE;
1074 
1075  vector v(pt - point1_);
1076 
1077  // Decompose sample-point1 into normal and parallel component
1078  const scalar parallel = (v & unitDir_);
1079 
1080  // Quick rejection. Left of point1 endcap, or right of point2 endcap
1081  if (parallel < 0 || parallel > magDir_)
1082  {
1083  continue;
1084  }
1085 
1086  const scalar radius_sec =
1087  radius1_ + parallel * (radius2_-radius1_)/magDir_;
1088 
1089  const scalar radius_sec_inner =
1090  innerRadius1_ + parallel * (innerRadius2_-innerRadius1_)/magDir_;
1091 
1092  // Remove the parallel component
1093  v -= parallel*unitDir_;
1094 
1095  if (mag(v) >= radius_sec_inner && mag(v) <= radius_sec)
1096  {
1097  volType[pointi] = volumeType::INSIDE;
1098  }
1099  }
1100 }
1101 
1102 
1103 // ************************************************************************* //
List< ReturnType > get(const UPtrList< T > &list, const AccessOp &aop)
List of values generated by applying the access operation to each list item.
dictionary dict
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:129
virtual tmp< pointField > points() const
Get the points that define the surface.
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
dimensionedSymmTensor sqr(const dimensionedVector &dv)
virtual void rename(const word &newName)
Rename the object.
Definition: IOobject.H:677
scalarField samples(nIntervals, Zero)
dimensionedScalar sqrt(const dimensionedScalar &ds)
PointIndexHit< point > pointIndexHit
A PointIndexHit with a 3D point.
Definition: pointIndexHit.H:58
A bounding box defined in terms of min/max extrema points.
Definition: boundBox.H:63
This class describes the interaction of an object (often a face) and a point. It carries the info of ...
Definition: pointIndexHit.H:44
Base class of (analytical or triangulated) surface. Encapsulates all the search routines. WIP.
virtual void findLine(const pointField &start, const pointField &end, List< pointIndexHit > &) const
Find nearest intersection on line from start to end.
quaternion normalised(const quaternion &q)
Return the normalised (unit) quaternion of the given quaternion.
Definition: quaternionI.H:674
virtual const wordList & regions() const
Names of regions.
virtual void getRegion(const List< pointIndexHit > &, labelList &region) const
From a set of points and indices get the region.
Macros for easy insertion into run-time selection tables.
addNamedToRunTimeSelectionTable(topoSetCellSource, badQualityToCell, word, badQuality)
virtual void getVolumeType(const pointField &points, List< volumeType > &volType) const
Determine type (inside/outside/mixed) for point.
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
label findMin(const ListType &input, label start=0)
Linear search for the index of the min element, similar to std::min_element but for lists and returns...
scalar y
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:38
void setSize(const label n)
Alias for resize()
Definition: List.H:316
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
const pointField & points
const dimensionedScalar b
Wien displacement law constant: default SI units: [m.K].
Definition: createFields.H:27
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
virtual void findNearest(const pointField &sample, const scalarField &nearestDistSqr, List< pointIndexHit > &) const
Find nearest point on cylinder.
static tmp< T > New(Args &&... args)
Construct tmp with forwarding arguments.
Definition: tmp.H:206
Vector< scalar > vector
Definition: vector.H:57
A location inside the volume.
Definition: volumeType.H:65
virtual void boundingSpheres(pointField &centres, scalarField &radiusSqr) const
Get bounding spheres (centre and radius squared), one per element.
A location outside the volume.
Definition: volumeType.H:66
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:26
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
virtual void getNormal(const List< pointIndexHit > &, vectorField &normal) const
From a set of points and indices get the normal.
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
const dimensionedScalar c
Speed of light in a vacuum.
virtual void findLineAny(const pointField &start, const pointField &end, List< pointIndexHit > &) const
Find any intersection on line from start to end.
virtual tmp< pointField > coordinates() const
Get representative set of element coordinates.
List< label > labelList
A List of labels.
Definition: List.H:62
volScalarField & p
IOobject io("surfaceFilmProperties", mesh.time().constant(), mesh, IOobject::READ_IF_PRESENT, IOobject::NO_WRITE, IOobject::NO_REGISTER)
A class for managing temporary objects.
Definition: HashPtrTable.H:50
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))
Defines the attributes of an object for which implicit objectRegistry management is supported...
Definition: IOobject.H:172
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
Namespace for OpenFOAM.
dimensionSet clamp(const dimensionSet &a, const dimensionSet &range)
Definition: dimensionSet.C:271
addToRunTimeSelectionTable(functionObject, pointHistory, dictionary)
const pointField & pts
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127