1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | foam-extend: Open Source CFD
4 \\ / O peration | Version: 3.2
5 \\ / A nd | Web: http://www.foam-extend.org
6 \\/ M anipulation | For copyright notice see file Copyright
7 -------------------------------------------------------------------------------
9 This file is part of foam-extend.
11 foam-extend is free software: you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by the
13 Free Software Foundation, either version 3 of the License, or (at your
14 option) any later version.
16 foam-extend is distributed in the hope that it will be useful, but
17 WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with foam-extend. If not, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
26 #include "searchableCylinder.H"
27 #include "addToRunTimeSelectionTable.H"
29 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
34 defineTypeNameAndDebug(searchableCylinder, 0);
35 addToRunTimeSelectionTable(searchableSurface, searchableCylinder, dict);
40 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
42 Foam::pointField Foam::searchableCylinder::coordinates() const
44 pointField ctrs(1, 0.5*(point1_ + point2_));
50 Foam::pointIndexHit Foam::searchableCylinder::findNearest
53 const scalar nearestDistSqr
56 pointIndexHit info(false, sample, -1);
58 vector v(sample - point1_);
60 // Decompose sample-point1 into normal and parallel component
61 scalar parallel = (v & unitDir_);
63 // Remove the parallel component
64 v -= parallel*unitDir_;
69 // nearest is at point1 end cap. Clip to radius.
70 if (magV < ROOTVSMALL)
72 info.setPoint(point1_);
76 //info.setPoint(point1_ + min(magV, radius_)*v/magV);
77 info.setPoint(point1_ + radius_*(v/magV));
80 else if (parallel >= magDir_)
82 // nearest is at point2
83 if (magV < ROOTVSMALL)
85 info.setPoint(point2_);
89 info.setPoint(point2_ + min(magV, radius_)*v/magV);
94 if (magV < ROOTVSMALL)
96 info.setPoint(point1_ + parallel*unitDir_);
100 // Project onto radius
101 info.setPoint(point1_ + parallel*unitDir_ + radius_*v/magV);
105 if (magSqr(sample - info.rawPoint()) < nearestDistSqr)
115 Foam::scalar Foam::searchableCylinder::radius2(const point& pt) const
117 const vector x = (pt-point1_) ^ unitDir_;
122 // From http://www.gamedev.net/community/forums/topic.asp?topic_id=467789 -
123 // intersection of cylinder with ray
124 void Foam::searchableCylinder::findLineAll
135 vector point1Start(start-point1_);
136 vector point2Start(start-point2_);
137 vector point1End(end-point1_);
139 // Quick rejection of complete vector outside endcaps
140 scalar s1 = point1Start&unitDir_;
141 scalar s2 = point1End&unitDir_;
143 if ((s1 < 0 && s2 < 0) || (s1 > magDir_ && s2 > magDir_))
148 // Line as P = start+t*V where V is unit vector and t=[0..mag(end-start)]
150 scalar magV = mag(V);
151 if (magV < ROOTVSMALL)
158 // We now get the nearest intersections to start. This can either be
159 // the intersection with the end plane or with the cylinder side.
161 // Get the two points (expressed in t) on the end planes. This is to
162 // clip any cylinder intersection against.
166 // Maintain the two intersections with the endcaps
167 scalar tNear = VGREAT;
168 scalar tFar = VGREAT;
171 scalar s = (V&unitDir_);
175 tPoint2 = -(point2Start&unitDir_)/s;
176 if (tPoint2 < tPoint1)
178 Swap(tPoint1, tPoint2);
180 if (tPoint1 > magV || tPoint2 < 0)
185 // See if the points on the endcaps are actually inside the cylinder
186 if (tPoint1 >= 0 && tPoint1 <= magV)
188 if (radius2(start+tPoint1*V) <= sqr(radius_))
193 if (tPoint2 >= 0 && tPoint2 <= magV)
195 if (radius2(start+tPoint2*V) <= sqr(radius_))
197 // Check if already have a near hit from point1
211 // Vector perpendicular to cylinder. Check for outside already done
212 // above so just set tpoint to allow all.
219 const vector x = point1Start ^ unitDir_;
220 const vector y = V ^ unitDir_;
221 const scalar d = sqr(radius_);
223 // Second order equation of the form a*t^2 + b*t + c
224 const scalar a = (y&y);
225 const scalar b = 2*(x&y);
226 const scalar c = (x&x)-d;
228 const scalar disc = b*b-4*a*c;
238 else if (disc < ROOTVSMALL)
241 if (mag(a) > ROOTVSMALL)
245 //Pout<< "single solution t:" << t1
246 // << " for start:" << start << " end:" << end
247 // << " c:" << c << endl;
249 if (t1 >= 0 && t1 <= magV && t1 >= tPoint1 && t1 <= tPoint2)
251 // valid. Insert sorted.
269 // Aligned with axis. Check if outside radius
270 //Pout<< "small discriminant:" << disc
271 // << " for start:" << start << " end:" << end
272 // << " magV:" << magV
273 // << " c:" << c << endl;
282 if (mag(a) > ROOTVSMALL)
284 scalar sqrtDisc = sqrt(disc);
286 t1 = (-b - sqrtDisc)/(2*a);
287 t2 = (-b + sqrtDisc)/(2*a);
293 if (t1 >= 0 && t1 <= magV && t1 >= tPoint1 && t1 <= tPoint2)
295 // valid. Insert sorted.
306 if (t2 >= 0 && t2 <= magV && t2 >= tPoint1 && t2 <= tPoint2)
308 // valid. Insert sorted.
319 //Pout<< "two solutions t1:" << t1 << " t2:" << t2
320 // << " for start:" << start << " end:" << end
321 // << " magV:" << magV
322 // << " c:" << c << endl;
326 // Aligned with axis. Check if outside radius
327 //Pout<< "large discriminant:" << disc
328 // << " small a:" << a
329 // << " for start:" << start << " end:" << end
330 // << " magV:" << magV
331 // << " c:" << c << endl;
340 if (tNear >= 0 && tNear <= magV)
342 near.setPoint(start+tNear*V);
348 far.setPoint(start+tFar*V);
353 else if (tFar >= 0 && tFar <= magV)
355 near.setPoint(start+tFar*V);
362 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
364 Foam::searchableCylinder::searchableCylinder
372 searchableSurface(io),
375 magDir_(mag(point2_-point1_)),
376 unitDir_((point2_-point1_)/magDir_),
381 Foam::searchableCylinder::searchableCylinder
384 const dictionary& dict
387 searchableSurface(io),
388 point1_(dict.lookup("point1")),
389 point2_(dict.lookup("point2")),
390 magDir_(mag(point2_-point1_)),
391 unitDir_((point2_-point1_)/magDir_),
392 radius_(readScalar(dict.lookup("radius")))
396 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
398 Foam::searchableCylinder::~searchableCylinder()
402 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
404 const Foam::wordList& Foam::searchableCylinder::regions() const
406 if (regions_.empty())
409 regions_[0] = "region0";
415 void Foam::searchableCylinder::findNearest
417 const pointField& samples,
418 const scalarField& nearestDistSqr,
419 List<pointIndexHit>& info
422 info.setSize(samples.size());
426 info[i] = findNearest(samples[i], nearestDistSqr[i]);
431 void Foam::searchableCylinder::findLine
433 const pointField& start,
434 const pointField& end,
435 List<pointIndexHit>& info
438 info.setSize(start.size());
442 // Pick nearest intersection. If none intersected take second one.
444 findLineAll(start[i], end[i], info[i], b);
445 if (!info[i].hit() && b.hit())
453 void Foam::searchableCylinder::findLineAny
455 const pointField& start,
456 const pointField& end,
457 List<pointIndexHit>& info
460 info.setSize(start.size());
464 // Discard far intersection
466 findLineAll(start[i], end[i], info[i], b);
467 if (!info[i].hit() && b.hit())
475 void Foam::searchableCylinder::findLineAll
477 const pointField& start,
478 const pointField& end,
479 List<List<pointIndexHit> >& info
482 info.setSize(start.size());
486 pointIndexHit near, far;
487 findLineAll(start[i], end[i], near, far);
519 void Foam::searchableCylinder::getRegion
521 const List<pointIndexHit>& info,
525 region.setSize(info.size());
530 void Foam::searchableCylinder::getNormal
532 const List<pointIndexHit>& info,
536 normal.setSize(info.size());
537 normal = vector::zero;
543 vector v(info[i].hitPoint() - point1_);
545 // Decompose sample-point1 into normal and parallel component
546 scalar parallel = v & unitDir_;
550 normal[i] = -unitDir_;
552 else if (parallel > magDir_)
554 normal[i] = -unitDir_;
558 // Remove the parallel component
559 v -= parallel*unitDir_;
560 normal[i] = v/mag(v);
567 void Foam::searchableCylinder::getVolumeType
569 const pointField& points,
570 List<volumeType>& volType
573 volType.setSize(points.size());
576 forAll(points, pointI)
578 const point& pt = points[pointI];
580 vector v(pt - point1_);
582 // Decompose sample-point1 into normal and parallel component
583 scalar parallel = v & unitDir_;
587 // left of point1 endcap
588 volType[pointI] = OUTSIDE;
590 else if (parallel > magDir_)
592 // right of point2 endcap
593 volType[pointI] = OUTSIDE;
597 // Remove the parallel component
598 v -= parallel*unitDir_;
600 if (mag(v) > radius_)
602 volType[pointI] = OUTSIDE;
606 volType[pointI] = INSIDE;
613 // ************************************************************************* //