diff --git a/src/meshTools/Make/files b/src/meshTools/Make/files
index bd0abc24a9..23b11884e2 100644
--- a/src/meshTools/Make/files
+++ b/src/meshTools/Make/files
@@ -65,6 +65,7 @@ searchableSurface = searchableSurface
$(searchableSurface)/searchableBox.C
$(searchableSurface)/searchableRotatedBox.C
$(searchableSurface)/searchableCylinder.C
+$(searchableSurface)/searchableCone.C
$(searchableSurface)/searchableDisk.C
$(searchableSurface)/searchablePlane.C
$(searchableSurface)/searchablePlate.C
diff --git a/src/meshTools/searchableSurface/searchableCone.C b/src/meshTools/searchableSurface/searchableCone.C
new file mode 100644
index 0000000000..c1047f8ec7
--- /dev/null
+++ b/src/meshTools/searchableSurface/searchableCone.C
@@ -0,0 +1,1126 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
+ \\ / O peration |
+ \\ / A nd | Copyright (C) 2015 OpenCFD Ltd.
+ \\/ M anipulation |
+-------------------------------------------------------------------------------
+License
+ This file is part of OpenFOAM.
+
+ OpenFOAM is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with OpenFOAM. If not, see .
+
+\*---------------------------------------------------------------------------*/
+
+#include "searchableCone.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+defineTypeNameAndDebug(searchableCone, 0);
+addToRunTimeSelectionTable(searchableSurface, searchableCone, dict);
+
+}
+
+
+// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
+
+Foam::tmp Foam::searchableCone::coordinates() const
+{
+ tmp tCtrs(new pointField(1, 0.5*(point1_ + point2_)));
+
+ return tCtrs;
+}
+
+
+void Foam::searchableCone::boundingSpheres
+(
+ pointField& centres,
+ scalarField& radiusSqr
+) const
+{
+ centres.setSize(1);
+ centres[0] = 0.5*(point1_ + point2_);
+
+ radiusSqr.setSize(1);
+ if (radius1_ > radius2_)
+ {
+ radiusSqr[0] = Foam::magSqr(point1_-centres[0]) + Foam::sqr(radius1_);
+ }
+ else
+ {
+ radiusSqr[0] = Foam::magSqr(point2_-centres[0]) + Foam::sqr(radius2_);
+ }
+
+ // Add a bit to make sure all points are tested inside
+ radiusSqr += Foam::sqr(SMALL);
+}
+
+
+Foam::tmp Foam::searchableCone::points() const
+{
+ tmp tPts(new pointField(2));
+ pointField& pts = tPts();
+
+ pts[0] = point1_;
+ pts[1] = point2_;
+
+ return tPts;
+}
+
+
+void Foam::searchableCone::findNearest
+(
+ const point& sample,
+ const scalar nearestDistSqr,
+ pointIndexHit& info,
+ vector& nearNormal
+) const
+{
+ vector v(sample - point1_);
+
+ // Decompose sample-point1 into normal and parallel component
+ scalar parallel = (v & unitDir_);
+
+ // Remove the parallel component and normalise
+ v -= parallel*unitDir_;
+
+ scalar magV = mag(v);
+ if (magV < ROOTVSMALL)
+ {
+ v = vector::zero;
+ }
+ else
+ {
+ v /= magV;
+ }
+
+ // Nearest and normal on disk at point1
+ point disk1Point(point1_ + min(max(magV, innerRadius1_), radius1_)*v);
+ vector disk1Normal(-unitDir_);
+
+ // Nearest and normal on disk at point2
+ point disk2Point(point2_ + min(max(magV, innerRadius2_), radius2_)*v);
+ vector disk2Normal(unitDir_);
+
+ // Nearest and normal on cone. Initialise to far-away point so if not
+ // set it picks one of the disk points
+ point nearCone(GREAT, GREAT, GREAT);
+ vector normalCone(1, 0, 0);
+
+ // Nearest and normal on inner cone. Initialise to far-away point
+ point iCnearCone(GREAT, GREAT, GREAT);
+ vector iCnormalCone(1, 0, 0);
+
+ point projPt1 = point1_+ radius1_*v;
+ point projPt2 = point2_+ radius2_*v;
+
+ vector p1 = (projPt1 - point1_);
+ if (mag(p1) > ROOTVSMALL)
+ {
+ p1 /= mag(p1);
+
+ // Find vector along the two end of cone
+ vector b(projPt2 - projPt1);
+ scalar magS = mag(b);
+ b /= magS;
+
+ // Find the vector along sample pt and pt at one end of conde
+ vector a(sample - projPt1);
+
+ if (mag(a) <= ROOTVSMALL)
+ {
+ // Exception: sample on disk1. Redo with projPt2.
+ vector a(sample - projPt2);
+ // Find normal unitvector
+ nearCone = (a & b)*b+projPt2;
+ vector b1 = (p1 & b)*b;
+ normalCone = p1 - b1;
+ normalCone /= mag(normalCone);
+ }
+ else
+ {
+ // Find neartest point on cone surface
+ nearCone = (a & b)*b+projPt1;
+ // Find projection along surface of cone
+ vector b1 = (p1 & b)*b;
+ normalCone = p1 - b1;
+ normalCone /= mag(normalCone);
+ }
+
+ if (innerRadius1_ > 0 && innerRadius2_ > 0)
+ {
+ // Same for inner radius
+ point iCprojPt1 = point1_+ innerRadius1_*v;
+ point iCprojPt2 = point2_+ innerRadius2_*v;
+
+ vector iCp1 = (iCprojPt1 - point1_);
+ iCp1 /= mag(iCp1);
+
+ // Find vector along the two end of cone
+ vector iCb(iCprojPt2 - iCprojPt1);
+ magS = mag(iCb);
+ iCb /= magS;
+
+
+ // Find the vector along sample pt and pt at one end of conde
+ vector iCa(sample - iCprojPt1);
+
+ if (mag(iCa) <= ROOTVSMALL)
+ {
+ vector iCa(sample - iCprojPt2);
+
+ // Find normal unitvector
+ iCnearCone = (iCa & iCb)*iCb+iCprojPt2;
+ vector b1 = (iCp1 & iCb)*iCb;
+ iCnormalCone = iCp1 - b1;
+ iCnormalCone /= mag(iCnormalCone);
+ }
+ else
+ {
+ // Find nearest point on cone surface
+ iCnearCone = (iCa & iCb)*iCb+iCprojPt1;
+ // Find projection along surface of cone
+ vector b1 = (iCp1 & iCb)*iCb;
+ iCnormalCone = iCp1 - b1;
+ iCnormalCone /= mag(iCnormalCone);
+ }
+ }
+ }
+
+
+ // Select nearest out of the 4 points (outer cone, disk1, disk2, inner
+ // cone)
+
+ FixedList dist;
+ dist[0] = magSqr(nearCone-sample);
+ dist[1] = magSqr(disk1Point-sample);
+ dist[2] = magSqr(disk2Point-sample);
+ dist[3] = magSqr(iCnearCone-sample);
+
+ label minI = findMin(dist);
+
+
+ // Snap the point to the corresponding surface
+
+ if (minI == 0) // Outer cone
+ {
+ // Closest to (infinite) outer cone. See if needs clipping to end disks
+
+ {
+ vector v1(nearCone-point1_);
+ scalar para = (v1 & unitDir_);
+ // Remove the parallel component and normalise
+ v1 -= para*unitDir_;
+ scalar magV1 = mag(v1);
+ v1 = v1/magV1;
+ if (para < 0.0 && magV1 >= radius1_)
+ {
+ // Near point 1. Set point to intersection of disk and cone.
+ // Keep normal from cone.
+ nearCone = disk1Point;
+ }
+ else if (para < 0.0 && magV1 < radius1_)
+ {
+ // On disk1
+ nearCone = disk1Point;
+ normalCone = disk1Normal;
+ }
+ else if (para > magDir_ && magV1 >= radius2_)
+ {
+ // Near point 2. Set point to intersection of disk and cone.
+ // Keep normal from cone.
+ nearCone = disk2Point;
+ }
+ else if (para > magDir_ && magV1 < radius2_)
+ {
+ // On disk2
+ nearCone = disk2Point;
+ normalCone = disk2Normal;
+ }
+ }
+ info.setPoint(nearCone);
+ nearNormal = normalCone;
+ }
+ else if (minI == 1) // Near to disk1
+ {
+ info.setPoint(disk1Point);
+ nearNormal = disk1Normal;
+ }
+ else if (minI == 2) // Near to disk2
+ {
+ info.setPoint(disk2Point);
+ nearNormal = disk2Normal;
+ }
+ else // Near to inner cone
+ {
+ {
+ vector v1(iCnearCone-point1_);
+ scalar para = (v1 & unitDir_);
+ // Remove the parallel component and normalise
+ v1 -= para*unitDir_;
+ scalar magV1 = mag(v1);
+ v1 = v1/magV1;
+
+ if (para < 0.0 && magV1 >= innerRadius1_)
+ {
+ iCnearCone = disk1Point;
+ }
+ else if (para < 0.0 && magV1 < innerRadius1_)
+ {
+ iCnearCone = disk1Point;
+ iCnormalCone = disk1Normal;
+ }
+ else if (para > magDir_ && magV1 >= innerRadius2_)
+ {
+ iCnearCone = disk2Point;
+ }
+ else if (para > magDir_ && magV1 < innerRadius2_)
+ {
+ iCnearCone = disk2Point;
+ iCnormalCone = disk2Normal;
+ }
+ }
+ info.setPoint(iCnearCone);
+ nearNormal = iCnormalCone;
+ }
+
+
+ if (magSqr(sample - info.rawPoint()) < nearestDistSqr)
+ {
+ info.setHit();
+ info.setIndex(0);
+ }
+}
+
+
+Foam::scalar Foam::searchableCone::radius2
+(
+ const searchableCone& cone,
+ const point& pt
+)
+{
+ const vector x = (pt-cone.point1_) ^ cone.unitDir_;
+ return x&x;
+}
+
+
+// From http://www.gamedev.net/community/forums/topic.asp?topic_id=467789 -
+// intersection of cylinder with ray
+void Foam::searchableCone::findLineAll
+(
+ const searchableCone& cone,
+ const scalar innerRadius1,
+ const scalar innerRadius2,
+ const point& start,
+ const point& end,
+ pointIndexHit& near,
+ pointIndexHit& far
+) const
+{
+ near.setMiss();
+ far.setMiss();
+
+ vector point1Start(start-cone.point1_);
+ vector point2Start(start-cone.point2_);
+ vector point1End(end-cone.point1_);
+
+ // Quick rejection of complete vector outside endcaps
+ scalar s1 = point1Start&(cone.unitDir_);
+ scalar s2 = point1End&(cone.unitDir_);
+
+ if ((s1 < 0.0 && s2 < 0.0) || (s1 > cone.magDir_ && s2 > cone.magDir_))
+ {
+ return;
+ }
+
+ // Line as P = start+t*V where V is unit vector and t=[0..mag(end-start)]
+ vector V(end-start);
+ scalar magV = mag(V);
+ if (magV < ROOTVSMALL)
+ {
+ return;
+ }
+ V /= magV;
+
+
+ // We now get the nearest intersections to start. This can either be
+ // the intersection with the end plane or with the cylinder side.
+
+ // Get the two points (expressed in t) on the end planes. This is to
+ // clip any cylinder intersection against.
+ scalar tPoint1;
+ scalar tPoint2;
+
+ // Maintain the two intersections with the endcaps
+ scalar tNear = VGREAT;
+ scalar tFar = VGREAT;
+
+ scalar radius_sec = cone.radius1_;
+
+ {
+ // Find dot product: mag(s)>VSMALL suggest that it is greater
+ scalar s = (V&unitDir_);
+ if (mag(s) > VSMALL)
+ {
+ tPoint1 = -s1/s;
+ tPoint2 = -(point2Start&(cone.unitDir_))/s;
+
+ if (tPoint2 < tPoint1)
+ {
+ Swap(tPoint1, tPoint2);
+ }
+ if (tPoint1 > magV || tPoint2 < 0)
+ {
+ return;
+ }
+ // See if the points on the endcaps are actually inside the cylinder
+ if (tPoint1 >= 0 && tPoint1 <= magV)
+ {
+ scalar r2 = radius2(cone, start+tPoint1*V);
+ vector p1 = (start+tPoint1*V-point1_);
+ vector p2 = (start+tPoint1*V-point2_);
+ radius_sec = cone.radius1_;
+ scalar inC_radius_sec = innerRadius1_;
+
+ if (mag(p2&(cone.unitDir_)) < mag(p1&(cone.unitDir_)))
+ {
+ radius_sec = cone.radius2_;
+ inC_radius_sec = innerRadius2_;
+ }
+
+ if (r2 <= sqr(radius_sec) && r2 >= sqr(inC_radius_sec))
+ {
+ tNear = tPoint1;
+ }
+ }
+ if (tPoint2 >= 0 && tPoint2 <= magV)
+ {
+ // Decompose sample-point1 into normal and parallel component
+ vector p1 = (start+tPoint2*V-cone.point1_);
+ vector p2 = (start+tPoint2*V-cone.point2_);
+ radius_sec = cone.radius1_;
+ scalar inC_radius_sec = innerRadius1_;
+ if (mag(p2&(cone.unitDir_)) < mag(p1&(cone.unitDir_)))
+ {
+ radius_sec = cone.radius2_;
+ inC_radius_sec = innerRadius2_;
+ }
+ scalar r2 = radius2(cone, start+tPoint2*V);
+ if (r2 <= sqr(radius_sec) && r2 >= sqr(inC_radius_sec))
+ {
+ // Check if already have a near hit from point1
+ if (tNear <= 1)
+ {
+ tFar = tPoint2;
+ }
+ else
+ {
+ tNear = tPoint2;
+ }
+ }
+ }
+ }
+ else
+ {
+ // Vector perpendicular to cylinder. Check for outside already done
+ // above so just set tpoint to allow all.
+ tPoint1 = -VGREAT;
+ tPoint2 = VGREAT;
+ }
+ }
+
+
+ vector va = cone.unitDir_;
+ point pa =
+ cone.unitDir_*cone.radius1_*mag(cone.point2_-cone.point1_)
+ /(cone.radius1_-cone.radius2_)
+ +cone.point1_;
+
+ scalar deltaRadius = cone.radius2_-cone.radius1_;
+ scalar l2 = sqr(deltaRadius)+sqr(cone.magDir_);
+ scalar sqrCosAlpha = sqr(cone.magDir_)/l2;
+ scalar sqrSinAlpha = sqr(deltaRadius)/l2;
+
+
+ vector delP(start-pa);
+ vector v1(end-start);
+ v1 = v1/mag(v1);
+
+ scalar p = (va&v1);
+ vector a1 = (v1-p*va);
+ vector p1 = (delP-(delP&va)*va);
+ const scalar a = sqrCosAlpha*((v1-p*va)&(v1-p*va))-sqrSinAlpha*p*p;
+ const scalar b =
+ 2.0*sqrCosAlpha*(a1&p1)
+ -2.0*sqrSinAlpha*(v1&va)*(delP&va);
+ const scalar c =
+ sqrCosAlpha
+ *((delP-(delP&va)*va)&(delP-(delP&va)*va))
+ -sqrSinAlpha*sqr(delP&va);
+ const scalar disc = b*b-4.0*a*c;
+
+ scalar t1 = -VGREAT;
+ scalar t2 = VGREAT;
+
+ if (disc < 0)
+ {
+ // Fully outside
+ return;
+ }
+ else if (disc < ROOTVSMALL)
+ {
+ // Single solution
+ if (mag(a) > ROOTVSMALL)
+ {
+ t1 = -b/(2.0*a);
+
+ if (t1 >= 0.0 && t1 <= magV && t1 >= tPoint1 && t1 <= tPoint2)
+ {
+ // Valid. Insert sorted.
+ if (t1 < tNear)
+ {
+ tFar = tNear;
+ tNear = t1;
+ }
+ else if (t1 < tFar)
+ {
+ tFar = t1;
+ }
+ }
+ else
+ {
+ return;
+ }
+ }
+ else
+ {
+ // Aligned with axis. Check if outside radius
+ if (c > 0.0)
+ {
+ return;
+ }
+ }
+ }
+ else
+ {
+ if (mag(a) > ROOTVSMALL)
+ {
+ scalar sqrtDisc = sqrt(disc);
+
+ t1 = (-b - sqrtDisc)/(2.0*a);
+ t2 = (-b + sqrtDisc)/(2.0*a);
+ if (t2 < t1)
+ {
+ Swap(t1, t2);
+ }
+
+ if (t1 >= 0.0 && t1 <= magV && t1 >= tPoint1 && t1 <= tPoint2)
+ {
+ // Valid. Insert sorted.
+ if (t1 < tNear)
+ {
+ tFar = tNear;
+ tNear = t1;
+ }
+ else if (t1 < tFar)
+ {
+ tFar = t1;
+ }
+ }
+ if (t2>=0 && t2 <= magV && t2 >= tPoint1 && t2 <= tPoint2)
+ {
+ // Valid. Insert sorted.
+ if (t2 < tNear)
+ {
+ tFar = tNear;
+ tNear = t2;
+ }
+ else if (t2 < tFar)
+ {
+ tFar = t2;
+ }
+ }
+ }
+ else
+ {
+ // Aligned with axis. Check if outside radius
+ if (c > 0.0)
+ {
+ return;
+ }
+ }
+ }
+
+ // Check tNear, tFar
+ if (tNear>=0 && tNear <= magV)
+ {
+ near.setPoint(start+tNear*V);
+ near.setHit();
+ near.setIndex(0);
+ if (tFar <= magV)
+ {
+ far.setPoint(start+tFar*V);
+ far.setHit();
+ far.setIndex(0);
+ }
+ }
+ else if (tFar>=0 && tFar <= magV)
+ {
+ near.setPoint(start+tFar*V);
+ near.setHit();
+ near.setIndex(0);
+ }
+}
+
+
+void Foam::searchableCone::insertHit
+(
+ const point& start,
+ const point& end,
+ List& info,
+ const pointIndexHit& hit
+) const
+{
+ scalar smallDistSqr = SMALL*magSqr(end-start);
+
+ scalar hitMagSqr = magSqr(hit.hitPoint()-start);
+
+ forAll(info, i)
+ {
+ scalar d2 = magSqr(info[i].hitPoint()-start);
+
+ if (d2 > hitMagSqr+smallDistSqr)
+ {
+ // Insert at i.
+ label sz = info.size();
+ info.setSize(sz+1);
+ for (label j = sz; j > i; --j)
+ {
+ info[j] = info[j-1];
+ }
+ info[i] = hit;
+ return;
+ }
+ else if (d2 > hitMagSqr-smallDistSqr)
+ {
+ // hit is same point as info[i].
+ return;
+ }
+ }
+ // Append
+ label sz = info.size();
+ info.setSize(sz+1);
+ info[sz] = hit;
+}
+
+
+Foam::boundBox Foam::searchableCone::calcBounds() const
+{
+ // Adapted from
+ // http://www.gamedev.net/community/forums
+ // /topic.asp?topic_id=338522&forum_id=20&gforum_id=0
+
+ // Let cylinder have end points A,B and radius r,
+
+ // Bounds in direction X (same for Y and Z) can be found as:
+ // Let A.X= radius1_)
+ {
+ kr *= radius2_;
+ }
+ else
+ {
+ kr *= radius1_;
+ }
+
+ point min = point1_ - kr;
+ point max = point1_ + kr;
+
+ min = ::Foam::min(min, point2_ - kr);
+ max = ::Foam::max(max, point2_ + kr);
+
+ return boundBox(min, max);
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
+
+Foam::searchableCone::searchableCone
+(
+ const IOobject& io,
+ const point& point1,
+ const scalar radius1,
+ const scalar innerRadius1,
+ const point& point2,
+ const scalar radius2,
+ const scalar innerRadius2
+)
+:
+ searchableSurface(io),
+ point1_(point1),
+ radius1_(radius1),
+ innerRadius1_(innerRadius1),
+ point2_(point2),
+ radius2_(radius2),
+ innerRadius2_(innerRadius2),
+ magDir_(mag(point2_-point1_)),
+ unitDir_((point2_-point1_)/magDir_)
+{
+ bounds() = calcBounds();
+}
+
+
+Foam::searchableCone::searchableCone
+(
+ const IOobject& io,
+ const dictionary& dict
+)
+:
+ searchableSurface(io),
+ point1_(dict.lookup("point1")),
+ radius1_(readScalar(dict.lookup("radius1"))),
+ innerRadius1_(dict.lookupOrDefault("innerRadius1", 0.0)),
+ point2_(dict.lookup("point2")),
+ radius2_(readScalar(dict.lookup("radius2"))),
+ innerRadius2_(dict.lookupOrDefault("innerRadius2", 0.0)),
+ magDir_(mag(point2_-point1_)),
+ unitDir_((point2_-point1_)/magDir_)
+{
+ bounds() = calcBounds();
+}
+
+
+// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
+
+Foam::searchableCone::~searchableCone()
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
+
+const Foam::wordList& Foam::searchableCone::regions() const
+{
+ if (regions_.empty())
+ {
+ regions_.setSize(1);
+ regions_[0] = "region0";
+ }
+ return regions_;
+}
+
+
+void Foam::searchableCone::findNearest
+(
+ const pointField& samples,
+ const scalarField& nearestDistSqr,
+ List& info
+) const
+{
+ info.setSize(samples.size());
+ forAll(samples, i)
+ {
+ vector normal;
+ findNearest(samples[i], nearestDistSqr[i], info[i], normal);
+ }
+}
+
+
+void Foam::searchableCone::findLine
+(
+ const pointField& start,
+ const pointField& end,
+ List& info
+) const
+{
+ info.setSize(start.size());
+
+ forAll(start, i)
+ {
+ // Pick nearest intersection. If none intersected take second one.
+ pointIndexHit b;
+ findLineAll
+ (
+ *this,
+ innerRadius1_,
+ innerRadius2_,
+ start[i],
+ end[i],
+ info[i],
+ b
+ );
+ if (!info[i].hit() && b.hit())
+ {
+ info[i] = b;
+ }
+ }
+
+
+ if (innerRadius1_ > 0.0 && innerRadius2_ > 0.0)
+ {
+ IOobject io(*this);
+ io.rename(name()+"Inner");
+ searchableCone innerCone
+ (
+ io,
+ point1_,
+ innerRadius1_,
+ 0.0,
+ point2_,
+ innerRadius2_,
+ 0.0
+ );
+
+ forAll(info, i)
+ {
+ point newEnd;
+ if (info[i].hit())
+ {
+ newEnd = info[i].hitPoint();
+ }
+ else
+ {
+ newEnd = end[i];
+ }
+ pointIndexHit near;
+ pointIndexHit far;
+ findLineAll
+ (
+ innerCone,
+ innerRadius1_,
+ innerRadius2_,
+ start[i],
+ newEnd,
+ near,
+ far
+ );
+
+ if (near.hit())
+ {
+ info[i] = near;
+ }
+ else if (far.hit())
+ {
+ info[i] = far;
+ }
+ }
+ }
+}
+
+
+void Foam::searchableCone::findLineAny
+(
+ const pointField& start,
+ const pointField& end,
+ List& info
+) const
+{
+ info.setSize(start.size());
+
+ forAll(start, i)
+ {
+ // Discard far intersection
+ pointIndexHit b;
+ findLineAll
+ (
+ *this,
+ innerRadius1_,
+ innerRadius2_,
+ start[i],
+ end[i],
+ info[i],
+ b
+ );
+ if (!info[i].hit() && b.hit())
+ {
+ info[i] = b;
+ }
+ }
+ if (innerRadius1_ > 0.0 && innerRadius2_ > 0.0)
+ {
+ IOobject io(*this);
+ io.rename(name()+"Inner");
+ searchableCone cone
+ (
+ io,
+ point1_,
+ innerRadius1_,
+ 0.0,
+ point2_,
+ innerRadius2_,
+ 0.0
+ );
+
+ forAll(info, i)
+ {
+ if (!info[i].hit())
+ {
+ pointIndexHit b;
+ findLineAll
+ (
+ cone,
+ innerRadius1_,
+ innerRadius2_,
+ start[i],
+ end[i],
+ info[i],
+ b
+ );
+ if (!info[i].hit() && b.hit())
+ {
+ info[i] = b;
+ }
+ }
+ }
+ }
+}
+
+
+void Foam::searchableCone::findLineAll
+(
+ const pointField& start,
+ const pointField& end,
+ List >& info
+) const
+{
+ info.setSize(start.size());
+
+ forAll(start, i)
+ {
+ pointIndexHit near, far;
+ findLineAll
+ (
+ *this,
+ innerRadius1_,
+ innerRadius2_,
+ start[i],
+ end[i],
+ near,
+ far
+ );
+
+ if (near.hit())
+ {
+ if (far.hit())
+ {
+ info[i].setSize(2);
+ info[i][0] = near;
+ info[i][1] = far;
+ }
+ else
+ {
+ info[i].setSize(1);
+ info[i][0] = near;
+ }
+ }
+ else
+ {
+ if (far.hit())
+ {
+ info[i].setSize(1);
+ info[i][0] = far;
+ }
+ else
+ {
+ info[i].clear();
+ }
+ }
+ }
+
+ if (innerRadius1_ > 0.0 && innerRadius2_ > 0.0)
+ {
+ IOobject io(*this);
+ io.rename(name()+"Inner");
+ searchableCone cone
+ (
+ io,
+ point1_,
+ innerRadius1_,
+ 0.0,
+ point2_,
+ innerRadius2_,
+ 0.0
+ );
+
+ forAll(info, i)
+ {
+ pointIndexHit near;
+ pointIndexHit far;
+ findLineAll
+ (
+ cone,
+ innerRadius1_,
+ innerRadius2_,
+ start[i],
+ end[i],
+ near,
+ far
+ );
+
+ if (near.hit())
+ {
+ insertHit(start[i], end[i], info[i], near);
+ }
+ if (far.hit())
+ {
+ insertHit(start[i], end[i], info[i], far);
+ }
+ }
+ }
+}
+
+
+void Foam::searchableCone::getRegion
+(
+ const List& info,
+ labelList& region
+) const
+{
+ region.setSize(info.size());
+ region = 0;
+}
+
+
+void Foam::searchableCone::getNormal
+(
+ const List& info,
+ vectorField& normal
+) const
+{
+ normal.setSize(info.size());
+ normal = vector::zero;
+
+ forAll(info, i)
+ {
+ if (info[i].hit())
+ {
+ pointIndexHit nearInfo;
+ findNearest
+ (
+ info[i].hitPoint(),
+ Foam::sqr(GREAT),
+ nearInfo,
+ normal[i]
+ );
+ }
+ }
+}
+
+
+void Foam::searchableCone::getVolumeType
+(
+ const pointField& points,
+ List& volType
+) const
+{
+ volType.setSize(points.size());
+ volType = volumeType::INSIDE;
+
+ scalar magDir = magDir_;
+
+ bool swap = false;
+ bool swapInner = false;
+
+ if (radius1_ > radius2_)
+ {
+ swap = true;
+ }
+
+ if (innerRadius1_ > innerRadius2_)
+ {
+ swapInner = true;
+ }
+
+ forAll(points, pointI)
+ {
+ const point& pt = points[pointI];
+
+ vector v(pt - point1_);
+
+ // Decompose sample-point1 into normal and parallel component
+ scalar parallel = v & unitDir_;
+ scalar comp = parallel;
+ scalar compInner = parallel;
+ if (swap)
+ {
+ comp = -(magDir-parallel);
+ }
+
+ if (swapInner)
+ {
+ compInner = -(magDir-parallel);
+ }
+
+ scalar radius_sec = radius1_+comp*(radius2_-radius1_)/magDir_;
+
+ scalar radius_sec_inner =
+ innerRadius1_
+ +compInner*(innerRadius2_-innerRadius1_)/magDir_;
+
+ if (parallel < 0)
+ {
+ // Left of point1 endcap
+ volType[pointI] = volumeType::OUTSIDE;
+ }
+ else if (parallel > magDir_)
+ {
+ // Right of point2 endcap
+ volType[pointI] = volumeType::OUTSIDE;
+ }
+ else
+ {
+ // Remove the parallel component
+ v -= parallel*unitDir_;
+ if (mag(v) >= radius_sec_inner && mag(v) <= radius_sec)
+ {
+ volType[pointI] = volumeType::INSIDE;
+ }
+ else
+ {
+ volType[pointI] = volumeType::OUTSIDE;
+ }
+ }
+ }
+}
+
+
+// ************************************************************************* //
diff --git a/src/meshTools/searchableSurface/searchableCone.H b/src/meshTools/searchableSurface/searchableCone.H
new file mode 100644
index 0000000000..6e477bc405
--- /dev/null
+++ b/src/meshTools/searchableSurface/searchableCone.H
@@ -0,0 +1,296 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
+ \\ / O peration |
+ \\ / A nd | Copyright (C) 2015 OpenCFD Ltd.
+ \\/ M anipulation |
+-------------------------------------------------------------------------------
+License
+ This file is part of OpenFOAM.
+
+ OpenFOAM is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with OpenFOAM. If not, see .
+
+Class
+ Foam::searchableCone
+
+Description
+ Searching on (optionally hollow) cone.
+
+ \heading Function object usage
+ \table
+ Property | Description | Required | Default value
+ point1 | coordinate of endpoint | yes |
+ radius1 | radius at point1 | yes | yes
+ innerRadius1 | inner radius at point1 | no |
+ point2 | coordinate of endpoint | yes |
+ radius2 | radius at point2 | yes | yes
+ innerRadius2 | inner radius at point2 | no |
+ \endtable
+
+Note
+ Initial implementation, might suffer from robustness (e.g. radius1==radius2)
+
+SourceFiles
+ searchableCone.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef searchableCone_H
+#define searchableCone_H
+
+#include "searchableSurface.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+ Class searchableCone Declaration
+\*---------------------------------------------------------------------------*/
+
+class searchableCone
+:
+ public searchableSurface
+{
+ // Private Member Data
+
+ //- 'Left' point
+ const point point1_;
+
+ //- Outer radius at point1
+ const scalar radius1_;
+
+ //- Inner radius at point1
+ const scalar innerRadius1_;
+
+
+ //- 'Right' point
+ const point point2_;
+
+ //- Outer radius at point2
+ const scalar radius2_;
+
+ //- Inner radius at point2
+ const scalar innerRadius2_;
+
+
+ //- Length of vector point2-point1
+ const scalar magDir_;
+
+ //- Normalised vector point2-point1
+ const vector unitDir_;
+
+
+ //- Names of regions
+ mutable wordList regions_;
+
+
+ // Private Member Functions
+
+ //- Find nearest point on cylinder.
+ void findNearest
+ (
+ const point& sample,
+ const scalar nearestDistSqr,
+ pointIndexHit & nearInfo,
+ vector& normal
+ ) const;
+
+ //- Determine radial coordinate (squared)
+ static scalar radius2(const searchableCone& cone, const point& pt);
+
+ //- Find both intersections with cone. innerRadii supplied externally.
+ void findLineAll
+ (
+ const searchableCone& cone,
+ const scalar innerRadius1,
+ const scalar innerRadius2,
+ const point& start,
+ const point& end,
+ pointIndexHit& near,
+ pointIndexHit& far
+ ) const;
+
+ //- Insert a hit if it differs (by a tolerance) from the existing ones
+ void insertHit
+ (
+ const point& start,
+ const point& end,
+ List& info,
+ const pointIndexHit& hit
+ ) const;
+
+ //- Return the boundBox of the cylinder
+ boundBox calcBounds() const;
+
+ //- Disallow default bitwise copy construct
+ searchableCone(const searchableCone&);
+
+ //- Disallow default bitwise assignment
+ void operator=(const searchableCone&);
+
+
+public:
+
+ //- Runtime type information
+ TypeName("searchableCone");
+
+
+ // Constructors
+
+ //- Construct from components
+ searchableCone
+ (
+ const IOobject& io,
+ const point& point1,
+ const scalar radius1,
+ const scalar innerRadius1,
+ const point& point2,
+ const scalar radius2,
+ const scalar innerRadius2
+ );
+
+ //- Construct from dictionary (used by searchableSurface)
+ searchableCone
+ (
+ const IOobject& io,
+ const dictionary& dict
+ );
+
+
+ //- Destructor
+
+ virtual ~searchableCone();
+
+
+ // Member Functions
+
+ virtual const wordList& regions() const;
+
+ //- Whether supports volume type below
+ virtual bool hasVolumeType() const
+ {
+ return true;
+ }
+
+ //- Range of local indices that can be returned.
+ virtual label size() const
+ {
+ return 1;
+ }
+
+ //- Get representative set of element coordinates
+ // Usually the element centres (should be of length size()).
+ virtual tmp coordinates() const;
+
+ //- Get bounding spheres (centre and radius squared), one per element.
+ // Any point on element is guaranteed to be inside.
+ virtual void boundingSpheres
+ (
+ pointField& centres,
+ scalarField& radiusSqr
+ ) const;
+
+ //- Get the points that define the surface.
+ virtual tmp points() const;
+
+ //- Does any part of the surface overlap the supplied bound box?
+ virtual bool overlaps(const boundBox& bb) const
+ {
+ notImplemented
+ (
+ "searchableCone::overlaps(const boundBox&) const"
+ );
+
+ return false;
+ }
+
+
+ // Multiple point queries.
+
+ //- Find nearest point on cylinder
+ virtual void findNearest
+ (
+ const pointField& sample,
+ const scalarField& nearestDistSqr,
+ List&
+ ) const;
+
+ //- Find nearest intersection on line from start to end
+ virtual void findLine
+ (
+ const pointField& start,
+ const pointField& end,
+ List&
+ ) const;
+
+ //- Find any intersection on line from start to end
+ virtual void findLineAny
+ (
+ const pointField& start,
+ const pointField& end,
+ List&
+ ) const;
+
+ //- Find all intersections in order from start to end
+ virtual void findLineAll
+ (
+ const pointField& start,
+ const pointField& end,
+ List >&
+ ) const;
+
+ //- From a set of points and indices get the region
+ virtual void getRegion
+ (
+ const List&,
+ labelList& region
+ ) const;
+
+ //- From a set of points and indices get the normal
+ virtual void getNormal
+ (
+ const List&,
+ vectorField& normal
+ ) const;
+
+ //- Determine type (inside/outside/mixed) for point. unknown if
+ // cannot be determined (e.g. non-manifold surface)
+ virtual void getVolumeType
+ (
+ const pointField&,
+ List&
+ ) const;
+
+
+ // regIOobject implementation
+
+ bool writeData(Ostream&) const
+ {
+ notImplemented("searchableCone::writeData(Ostream&) const");
+ return false;
+ }
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //