1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright held by original author
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
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 the
13 Free Software Foundation; either version 2 of the License, or (at your
14 option) any later version.
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
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM; if not, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 \*---------------------------------------------------------------------------*/
27 #include "searchableCylinder.H"
28 #include "addToRunTimeSelectionTable.H"
30 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
35 defineTypeNameAndDebug(searchableCylinder, 0);
36 addToRunTimeSelectionTable(searchableSurface, searchableCylinder, dict);
41 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
43 Foam::pointField Foam::searchableCylinder::coordinates() const
45 pointField ctrs(1, 0.5*(point1_ + point2_));
51 Foam::pointIndexHit Foam::searchableCylinder::findNearest
54 const scalar nearestDistSqr
57 pointIndexHit info(false, sample, -1);
59 vector v(sample - point1_);
61 // Decompose sample-point1 into normal and parallel component
62 scalar parallel = (v & unitDir_);
64 // Remove the parallel component
65 v -= parallel*unitDir_;
70 // nearest is at point1 end cap. Clip to radius.
71 if (magV < ROOTVSMALL)
73 info.setPoint(point1_);
77 //info.setPoint(point1_ + min(magV, radius_)*v/magV);
78 info.setPoint(point1_ + radius_*(v/magV));
81 else if (parallel >= magDir_)
83 // nearest is at point2
84 if (magV < ROOTVSMALL)
86 info.setPoint(point2_);
90 info.setPoint(point2_ + min(magV, radius_)*v/magV);
95 if (magV < ROOTVSMALL)
97 info.setPoint(point1_ + parallel*unitDir_);
101 // Project onto radius
102 info.setPoint(point1_ + parallel*unitDir_ + radius_*v/magV);
106 if (magSqr(sample - info.rawPoint()) < nearestDistSqr)
116 Foam::scalar Foam::searchableCylinder::radius2(const point& pt) const
118 const vector x = (pt-point1_) ^ unitDir_;
123 // From http://www.gamedev.net/community/forums/topic.asp?topic_id=467789 -
124 // intersection of cylinder with ray
125 void Foam::searchableCylinder::findLineAll
136 vector point1Start(start-point1_);
137 vector point2Start(start-point2_);
138 vector point1End(end-point1_);
140 // Quick rejection of complete vector outside endcaps
141 scalar s1 = point1Start&unitDir_;
142 scalar s2 = point1End&unitDir_;
144 if ((s1 < 0 && s2 < 0) || (s1 > magDir_ && s2 > magDir_))
149 // Line as P = start+t*V where V is unit vector and t=[0..mag(end-start)]
151 scalar magV = mag(V);
152 if (magV < ROOTVSMALL)
159 // We now get the nearest intersections to start. This can either be
160 // the intersection with the end plane or with the cylinder side.
162 // Get the two points (expressed in t) on the end planes. This is to
163 // clip any cylinder intersection against.
167 // Maintain the two intersections with the endcaps
168 scalar tNear = VGREAT;
169 scalar tFar = VGREAT;
172 scalar s = (V&unitDir_);
176 tPoint2 = -(point2Start&unitDir_)/s;
177 if (tPoint2 < tPoint1)
179 Swap(tPoint1, tPoint2);
181 if (tPoint1 > magV || tPoint2 < 0)
186 // See if the points on the endcaps are actually inside the cylinder
187 if (tPoint1 >= 0 && tPoint1 <= magV)
189 if (radius2(start+tPoint1*V) <= sqr(radius_))
194 if (tPoint2 >= 0 && tPoint2 <= magV)
196 if (radius2(start+tPoint2*V) <= sqr(radius_))
198 // Check if already have a near hit from point1
212 // Vector perpendicular to cylinder. Check for outside already done
213 // above so just set tpoint to allow all.
220 const vector x = point1Start ^ unitDir_;
221 const vector y = V ^ unitDir_;
222 const scalar d = sqr(radius_);
224 // Second order equation of the form a*t^2 + b*t + c
225 const scalar a = (y&y);
226 const scalar b = 2*(x&y);
227 const scalar c = (x&x)-d;
229 const scalar disc = b*b-4*a*c;
239 else if (disc < ROOTVSMALL)
242 if (mag(a) > ROOTVSMALL)
246 //Pout<< "single solution t:" << t1
247 // << " for start:" << start << " end:" << end
248 // << " c:" << c << endl;
250 if (t1 >= 0 && t1 <= magV && t1 >= tPoint1 && t1 <= tPoint2)
252 // valid. Insert sorted.
270 // Aligned with axis. Check if outside radius
271 //Pout<< "small discriminant:" << disc
272 // << " for start:" << start << " end:" << end
273 // << " magV:" << magV
274 // << " c:" << c << endl;
283 if (mag(a) > ROOTVSMALL)
285 scalar sqrtDisc = sqrt(disc);
287 t1 = (-b - sqrtDisc)/(2*a);
288 t2 = (-b + sqrtDisc)/(2*a);
294 if (t1 >= 0 && t1 <= magV && t1 >= tPoint1 && t1 <= tPoint2)
296 // valid. Insert sorted.
307 if (t2 >= 0 && t2 <= magV && t2 >= tPoint1 && t2 <= tPoint2)
309 // valid. Insert sorted.
320 //Pout<< "two solutions t1:" << t1 << " t2:" << t2
321 // << " for start:" << start << " end:" << end
322 // << " magV:" << magV
323 // << " c:" << c << endl;
327 // Aligned with axis. Check if outside radius
328 //Pout<< "large discriminant:" << disc
329 // << " small a:" << a
330 // << " for start:" << start << " end:" << end
331 // << " magV:" << magV
332 // << " c:" << c << endl;
341 if (tNear >= 0 && tNear <= magV)
343 near.setPoint(start+tNear*V);
349 far.setPoint(start+tFar*V);
354 else if (tFar >= 0 && tFar <= magV)
356 near.setPoint(start+tFar*V);
363 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
365 Foam::searchableCylinder::searchableCylinder
373 searchableSurface(io),
376 magDir_(mag(point2_-point1_)),
377 unitDir_((point2_-point1_)/magDir_),
382 Foam::searchableCylinder::searchableCylinder
385 const dictionary& dict
388 searchableSurface(io),
389 point1_(dict.lookup("point1")),
390 point2_(dict.lookup("point2")),
391 magDir_(mag(point2_-point1_)),
392 unitDir_((point2_-point1_)/magDir_),
393 radius_(readScalar(dict.lookup("radius")))
397 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
399 Foam::searchableCylinder::~searchableCylinder()
403 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
405 const Foam::wordList& Foam::searchableCylinder::regions() const
407 if (regions_.empty())
410 regions_[0] = "region0";
416 void Foam::searchableCylinder::findNearest
418 const pointField& samples,
419 const scalarField& nearestDistSqr,
420 List<pointIndexHit>& info
423 info.setSize(samples.size());
427 info[i] = findNearest(samples[i], nearestDistSqr[i]);
432 void Foam::searchableCylinder::findLine
434 const pointField& start,
435 const pointField& end,
436 List<pointIndexHit>& info
439 info.setSize(start.size());
443 // Pick nearest intersection. If none intersected take second one.
445 findLineAll(start[i], end[i], info[i], b);
446 if (!info[i].hit() && b.hit())
454 void Foam::searchableCylinder::findLineAny
456 const pointField& start,
457 const pointField& end,
458 List<pointIndexHit>& info
461 info.setSize(start.size());
465 // Discard far intersection
467 findLineAll(start[i], end[i], info[i], b);
468 if (!info[i].hit() && b.hit())
476 void Foam::searchableCylinder::findLineAll
478 const pointField& start,
479 const pointField& end,
480 List<List<pointIndexHit> >& info
483 info.setSize(start.size());
487 pointIndexHit near, far;
488 findLineAll(start[i], end[i], near, far);
520 void Foam::searchableCylinder::getRegion
522 const List<pointIndexHit>& info,
526 region.setSize(info.size());
531 void Foam::searchableCylinder::getNormal
533 const List<pointIndexHit>& info,
537 normal.setSize(info.size());
538 normal = vector::zero;
544 vector v(info[i].hitPoint() - point1_);
546 // Decompose sample-point1 into normal and parallel component
547 scalar parallel = v & unitDir_;
551 normal[i] = -unitDir_;
553 else if (parallel > magDir_)
555 normal[i] = -unitDir_;
559 // Remove the parallel component
560 v -= parallel*unitDir_;
561 normal[i] = v/mag(v);
568 void Foam::searchableCylinder::getVolumeType
570 const pointField& points,
571 List<volumeType>& volType
574 volType.setSize(points.size());
577 forAll(points, pointI)
579 const point& pt = points[pointI];
581 vector v(pt - point1_);
583 // Decompose sample-point1 into normal and parallel component
584 scalar parallel = v & unitDir_;
588 // left of point1 endcap
589 volType[pointI] = OUTSIDE;
591 else if (parallel > magDir_)
593 // right of point2 endcap
594 volType[pointI] = OUTSIDE;
598 // Remove the parallel component
599 v -= parallel*unitDir_;
601 if (mag(v) > radius_)
603 volType[pointI] = OUTSIDE;
607 volType[pointI] = INSIDE;
614 // ************************************************************************* //