225 lines
6.6 KiB
C++
225 lines
6.6 KiB
C++
/*---------------------------------------------------------------------------*\
|
|
========= |
|
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
|
\\ / O peration | Website: https://openfoam.org
|
|
\\ / A nd | Copyright (C) 2022-2024 OpenFOAM Foundation
|
|
\\/ 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 <http://www.gnu.org/licenses/>.
|
|
|
|
\*---------------------------------------------------------------------------*/
|
|
|
|
#include "argList.H"
|
|
#include "boundSphere.H"
|
|
#include "clock.H"
|
|
#include "cpuTime.H"
|
|
#include "OBJstream.H"
|
|
#include "triFace.H"
|
|
|
|
using namespace Foam;
|
|
|
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
argList::validArgs.append("number of points");
|
|
argList::addOption
|
|
(
|
|
"nTests",
|
|
"value",
|
|
"number of tests - default is 1"
|
|
);
|
|
argList::addOption
|
|
(
|
|
"seed",
|
|
"value",
|
|
"random number generator seed - default is clock time"
|
|
);
|
|
|
|
Foam::argList args(argc, argv);
|
|
Info<< nl;
|
|
|
|
const label nPs = args.argRead<label>(1);
|
|
const label nTests = args.optionLookupOrDefault<label>("nTests", 1);
|
|
|
|
// Initialise the random number generator
|
|
label seed;
|
|
if (args.optionFound("seed"))
|
|
{
|
|
seed = args.optionRead<label>("seed");
|
|
}
|
|
else
|
|
{
|
|
seed = clock::getTime();
|
|
Info<< "Seeding random number generator with value " << seed
|
|
<< nl << endl;
|
|
}
|
|
|
|
// Do tests
|
|
List<point> ps;
|
|
Tuple2<point, scalar> sphere;
|
|
cpuTime time;
|
|
for (label testi = 0; testi < nTests; ++ testi)
|
|
{
|
|
randomGenerator rndGen(seed + testi);
|
|
|
|
// Get random points
|
|
ps.resize(nPs);
|
|
forAll(ps, i)
|
|
{
|
|
ps[i] = point::uniform(1);
|
|
|
|
while (magSqr(ps[i]) > 1)
|
|
{
|
|
ps[i] = 2*(rndGen.sample01<point>() - point::uniform(0.5));
|
|
}
|
|
}
|
|
|
|
// Determine the bounds
|
|
sphere = boundSphere(ps, rndGen);
|
|
|
|
// Check
|
|
forAll(ps, i)
|
|
{
|
|
if
|
|
(
|
|
magSqr(ps[i] - sphere.first())
|
|
> (1 + rootSmall)*sqr(sphere.second())
|
|
)
|
|
{
|
|
FatalErrorInFunction
|
|
<< "Sphere does not bound point " << i << '/' << nPs << " ("
|
|
<< magSqr(ps[i] - sphere.first())/sqr(sphere.second())
|
|
<< ")" << exit(FatalError);
|
|
}
|
|
}
|
|
|
|
if (nTests != 1)
|
|
{
|
|
Info<< "\rSuccessfully computed " << testi + 1 << " bound spheres";
|
|
}
|
|
}
|
|
|
|
// Report
|
|
if (nTests == 1)
|
|
{
|
|
Info<< "Bounding sphere with centre = " << sphere.first()
|
|
<< ", radius = " << sphere.second() << ", calculated in "
|
|
<< time.cpuTimeIncrement() << " s" << nl << endl;
|
|
|
|
// Write the points
|
|
OBJstream osPs(args[0] + "_points.obj");
|
|
Info<< "Writing points to " << osPs.name() << endl;
|
|
forAll(ps, i)
|
|
{
|
|
osPs.write(ps[i]);
|
|
}
|
|
|
|
// Write the sphere
|
|
OBJstream osSphere(args[0] + "_sphere.obj");
|
|
Info<< "Writing sphere to " << osSphere.name() << endl;
|
|
|
|
using namespace constant::mathematical;
|
|
|
|
static const label nRings = 20;
|
|
static const label nRing1Points = 4;
|
|
|
|
DynamicList<point> spherePs;
|
|
DynamicList<face> sphereTris;
|
|
auto appendP = [&](const scalar x, const scalar y, const scalar z)
|
|
{
|
|
spherePs.append(sphere.first() + sphere.second()*point(x, y, z));
|
|
spherePs.append(sphere.first() + sphere.second()*point(x, y, -z));
|
|
};
|
|
auto appendTri = [&](const label a, const label b, const label c)
|
|
{
|
|
sphereTris.append(triFace(2*a, 2*b, 2*c));
|
|
sphereTris.append(triFace(2*a + 1, 2*b + 1, 2*c + 1));
|
|
};
|
|
|
|
appendP(0, 0, 1);
|
|
|
|
label nPoints0 = 0, nPoints = 1;
|
|
|
|
for (label ringi = 1; ringi < nRings; ++ ringi)
|
|
{
|
|
const scalar rXY = Foam::sin(pi/2*ringi/(nRings - 1));
|
|
|
|
const label ringPN0 = max((ringi - 1)*nRing1Points, 1);
|
|
const label ringPN = ringi*nRing1Points;
|
|
|
|
label ringPi0 = 0, ringPi = 0;
|
|
|
|
for (label i = 0; i < nRing1Points; ++ i)
|
|
{
|
|
const scalar theta0 = 2*pi*i/nRing1Points;
|
|
const scalar theta1 = 2*pi*(i + 1)/nRing1Points;
|
|
|
|
for (label j = 0; j < ringi; ++ j)
|
|
{
|
|
const scalar f = scalar(j)/ringi;
|
|
const scalar theta = (1 - f)*theta0 + f*theta1;
|
|
|
|
const scalar x = rXY*Foam::cos(theta);
|
|
const scalar y = rXY*Foam::sin(theta);
|
|
const scalar z = Foam::sqrt(max(1 - sqr(x) - sqr(y), 0));
|
|
|
|
appendP(x, y, z);
|
|
|
|
appendTri
|
|
(
|
|
nPoints0 + (ringPi0 % ringPN0),
|
|
nPoints + ringPi,
|
|
nPoints + ((ringPi + 1) % ringPN)
|
|
);
|
|
|
|
if (ringi > 1 && j < ringi - 1)
|
|
{
|
|
appendTri
|
|
(
|
|
nPoints0 + (ringPi0 % ringPN0),
|
|
nPoints + ((ringPi + 1) % ringPN),
|
|
nPoints0 + ((ringPi0 + 1) % ringPN0)
|
|
);
|
|
}
|
|
|
|
if (j < ringi - 1) ringPi0 ++;
|
|
ringPi ++;
|
|
}
|
|
}
|
|
|
|
nPoints0 = nPoints;
|
|
nPoints += ringPi;
|
|
}
|
|
|
|
osSphere.write(faceList(sphereTris), pointField(spherePs), false);
|
|
}
|
|
else
|
|
{
|
|
Info<< nl << nl << "Bounding spheres calculated in "
|
|
<< time.cpuTimeIncrement() << " s" << endl;
|
|
}
|
|
|
|
Info<< nl << "End" << nl << endl;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
// ************************************************************************* //
|
|
|