1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2009 OpenCFD Ltd.
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::pointIndexHit Foam::searchableCylinder::findNearest
46 const scalar nearestDistSqr
49 pointIndexHit info(false, sample, -1);
51 vector v(sample - point1_);
53 // Decompose sample-point1 into normal and parallel component
54 scalar parallel = (v & unitDir_);
56 // Remove the parallel component
57 v -= parallel*unitDir_;
62 // nearest is at point1 end cap. Clip to radius.
63 if (magV < ROOTVSMALL)
65 info.setPoint(point1_);
69 //info.setPoint(point1_ + min(magV, radius_)*v/magV);
70 info.setPoint(point1_ + radius_*(v/magV));
73 else if (parallel >= magDir_)
75 // nearest is at point2
76 if (magV < ROOTVSMALL)
78 info.setPoint(point2_);
82 info.setPoint(point2_ + min(magV, radius_)*v/magV);
87 if (magV < ROOTVSMALL)
89 info.setPoint(point1_ + parallel*unitDir_);
93 // Project onto radius
94 info.setPoint(point1_ + parallel*unitDir_ + radius_*v/magV);
98 if (magSqr(sample - info.rawPoint()) < nearestDistSqr)
108 Foam::scalar Foam::searchableCylinder::radius2(const point& pt) const
110 const vector x = (pt-point1_) ^ unitDir_;
115 // From http://www.gamedev.net/community/forums/topic.asp?topic_id=467789 -
116 // intersection of cylinder with ray
117 void Foam::searchableCylinder::findLineAll
128 vector point1Start(start-point1_);
129 vector point2Start(start-point2_);
130 vector point1End(end-point1_);
132 // Quick rejection of complete vector outside endcaps
133 scalar s1 = point1Start&unitDir_;
134 scalar s2 = point1End&unitDir_;
136 if ((s1 < 0 && s2 < 0) || (s1 > magDir_ && s2 > magDir_))
141 // Line as P = start+t*V where V is unit vector and t=[0..mag(end-start)]
143 scalar magV = mag(V);
144 if (magV < ROOTVSMALL)
151 // We now get the nearest intersections to start. This can either be
152 // the intersection with the end plane or with the cylinder side.
154 // Get the two points (expressed in t) on the end planes. This is to
155 // clip any cylinder intersection against.
159 // Maintain the two intersections with the endcaps
160 scalar tNear = VGREAT;
161 scalar tFar = VGREAT;
164 scalar s = (V&unitDir_);
168 tPoint2 = -(point2Start&unitDir_)/s;
169 if (tPoint2 < tPoint1)
171 Swap(tPoint1, tPoint2);
173 if (tPoint1 > magV || tPoint2 < 0)
178 // See if the points on the endcaps are actually inside the cylinder
179 if (tPoint1 >= 0 && tPoint1 <= magV)
181 if (radius2(start+tPoint1*V) <= sqr(radius_))
186 if (tPoint2 >= 0 && tPoint2 <= magV)
188 if (radius2(start+tPoint2*V) <= sqr(radius_))
190 // Check if already have a near hit from point1
204 // Vector perpendicular to cylinder. Check for outside already done
205 // above so just set tpoint to allow all.
212 const vector x = point1Start ^ unitDir_;
213 const vector y = V ^ unitDir_;
214 const scalar d = sqr(radius_);
216 // Second order equation of the form a*t^2 + b*t + c
217 const scalar a = (y&y);
218 const scalar b = 2*(x&y);
219 const scalar c = (x&x)-d;
221 const scalar disc = b*b-4*a*c;
231 else if (disc < ROOTVSMALL)
234 if (mag(a) > ROOTVSMALL)
238 //Pout<< "single solution t:" << t1
239 // << " for start:" << start << " end:" << end
240 // << " c:" << c << endl;
242 if (t1 >= 0 && t1 <= magV && t1 >= tPoint1 && t1 <= tPoint2)
244 // valid. Insert sorted.
262 // Aligned with axis. Check if outside radius
263 //Pout<< "small discriminant:" << disc
264 // << " for start:" << start << " end:" << end
265 // << " magV:" << magV
266 // << " c:" << c << endl;
275 if (mag(a) > ROOTVSMALL)
277 scalar sqrtDisc = sqrt(disc);
279 t1 = (-b - sqrtDisc)/(2*a);
280 t2 = (-b + sqrtDisc)/(2*a);
286 if (t1 >= 0 && t1 <= magV && t1 >= tPoint1 && t1 <= tPoint2)
288 // valid. Insert sorted.
299 if (t2 >= 0 && t2 <= magV && t2 >= tPoint1 && t2 <= tPoint2)
301 // valid. Insert sorted.
312 //Pout<< "two solutions t1:" << t1 << " t2:" << t2
313 // << " for start:" << start << " end:" << end
314 // << " magV:" << magV
315 // << " c:" << c << endl;
319 // Aligned with axis. Check if outside radius
320 //Pout<< "large discriminant:" << disc
321 // << " small a:" << a
322 // << " for start:" << start << " end:" << end
323 // << " magV:" << magV
324 // << " c:" << c << endl;
333 if (tNear >= 0 && tNear <= magV)
335 near.setPoint(start+tNear*V);
341 far.setPoint(start+tFar*V);
346 else if (tFar >= 0 && tFar <= magV)
348 near.setPoint(start+tFar*V);
355 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
357 Foam::searchableCylinder::searchableCylinder
365 searchableSurface(io),
368 magDir_(mag(point2_-point1_)),
369 unitDir_((point2_-point1_)/magDir_),
374 Foam::searchableCylinder::searchableCylinder
377 const dictionary& dict
380 searchableSurface(io),
381 point1_(dict.lookup("point1")),
382 point2_(dict.lookup("point2")),
383 magDir_(mag(point2_-point1_)),
384 unitDir_((point2_-point1_)/magDir_),
385 radius_(readScalar(dict.lookup("radius")))
389 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
391 Foam::searchableCylinder::~searchableCylinder()
395 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
397 const Foam::wordList& Foam::searchableCylinder::regions() const
399 if (regions_.empty())
402 regions_[0] = "region0";
408 void Foam::searchableCylinder::findNearest
410 const pointField& samples,
411 const scalarField& nearestDistSqr,
412 List<pointIndexHit>& info
415 info.setSize(samples.size());
419 info[i] = findNearest(samples[i], nearestDistSqr[i]);
424 void Foam::searchableCylinder::findLine
426 const pointField& start,
427 const pointField& end,
428 List<pointIndexHit>& info
431 info.setSize(start.size());
435 // Pick nearest intersection. If none intersected take second one.
437 findLineAll(start[i], end[i], info[i], b);
438 if (!info[i].hit() && b.hit())
446 void Foam::searchableCylinder::findLineAny
448 const pointField& start,
449 const pointField& end,
450 List<pointIndexHit>& info
453 info.setSize(start.size());
457 // Discard far intersection
459 findLineAll(start[i], end[i], info[i], b);
460 if (!info[i].hit() && b.hit())
468 void Foam::searchableCylinder::findLineAll
470 const pointField& start,
471 const pointField& end,
472 List<List<pointIndexHit> >& info
475 info.setSize(start.size());
479 pointIndexHit near, far;
480 findLineAll(start[i], end[i], near, far);
512 void Foam::searchableCylinder::getRegion
514 const List<pointIndexHit>& info,
518 region.setSize(info.size());
523 void Foam::searchableCylinder::getNormal
525 const List<pointIndexHit>& info,
529 normal.setSize(info.size());
530 normal = vector::zero;
536 vector v(info[i].hitPoint() - point1_);
538 // Decompose sample-point1 into normal and parallel component
539 scalar parallel = v & unitDir_;
543 normal[i] = -unitDir_;
545 else if (parallel > magDir_)
547 normal[i] = -unitDir_;
551 // Remove the parallel component
552 v -= parallel*unitDir_;
553 normal[i] = v/mag(v);
560 void Foam::searchableCylinder::getVolumeType
562 const pointField& points,
563 List<volumeType>& volType
566 volType.setSize(points.size());
569 forAll(points, pointI)
571 const point& pt = points[pointI];
573 vector v(pt - point1_);
575 // Decompose sample-point1 into normal and parallel component
576 scalar parallel = v & unitDir_;
580 // left of point1 endcap
581 volType[pointI] = OUTSIDE;
583 else if (parallel > magDir_)
585 // right of point2 endcap
586 volType[pointI] = OUTSIDE;
590 // Remove the parallel component
591 v -= parallel*unitDir_;
593 if (mag(v) > radius_)
595 volType[pointI] = OUTSIDE;
599 volType[pointI] = INSIDE;
606 // ************************************************************************* //