You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
129 lines
5.0 KiB
129 lines
5.0 KiB
// David Eberly, Geometric Tools, Redmond WA 98052
|
|
// Copyright (c) 1998-2021
|
|
// Distributed under the Boost Software License, Version 1.0.
|
|
// https://www.boost.org/LICENSE_1_0.txt
|
|
// https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
|
|
// Version: 4.6.2020.02.05
|
|
|
|
#pragma once
|
|
|
|
#include <Mathematics/RootsBisection1.h>
|
|
#include <iomanip>
|
|
#include <sstream>
|
|
|
|
// Estimate a root to continuous functions F(x,y) and G(x,y) define on a
|
|
// rectangle [xMin,xMax]x[yMin,yMax]. The requirements are that for each
|
|
// y' in [yMin,yMax], A(x) = F(x,y') satisfies A(xMin) * A(xMax) < 0,
|
|
// which guarantees A(x) has a root. Also, for each x' in [xMin,xMax],
|
|
// B(y) = G(x',y) satisfies B(yMin) * B(yMax) < 0, which guarantees B(y)
|
|
// has a root. Bisection is performed in the x-direction for A(x). Let
|
|
// x' be the root. Bisection is then performed in the y-direction for
|
|
// B(y). Let y' be the root. The function value is A(x') = F(x',y').
|
|
// This effectively is a bisection of C(x) = F(x,h(x)) along the curve
|
|
// where G(x,h(x)) = 0.
|
|
|
|
namespace gte
|
|
{
|
|
template <typename Real>
|
|
class RootsBisection2
|
|
{
|
|
public:
|
|
// Use this constructor when Real is a floating-point type.
|
|
template <typename Dummy = Real>
|
|
RootsBisection2(uint32_t xMaxIterations, uint32_t yMaxIterations,
|
|
typename std::enable_if<!is_arbitrary_precision<Dummy>::value>::type* = nullptr)
|
|
:
|
|
mXBisector(xMaxIterations),
|
|
mYBisector(yMaxIterations),
|
|
mXRoot(0),
|
|
mYRoot(0),
|
|
mFAtRoot(0),
|
|
mGAtRoot(0)
|
|
{
|
|
static_assert(!is_arbitrary_precision<Real>::value,
|
|
"Template parameter is not a floating-point type.");
|
|
}
|
|
|
|
// Use this constructor when Real is an arbitrary-precision type.
|
|
template <typename Dummy = Real>
|
|
RootsBisection2(uint32_t precision, uint32_t xMaxIterations, uint32_t yMaxIterations,
|
|
typename std::enable_if<is_arbitrary_precision<Dummy>::value>::type* = nullptr)
|
|
:
|
|
mXBisector(precision, xMaxIterations),
|
|
mYBisector(precision, yMaxIterations),
|
|
mXRoot(0),
|
|
mYRoot(0),
|
|
mFAtRoot(0),
|
|
mGAtRoot(0)
|
|
{
|
|
static_assert(is_arbitrary_precision<Real>::value,
|
|
"Template parameter is not an arbitrary-precision type.");
|
|
}
|
|
|
|
// Disallow copy and move semantics.
|
|
RootsBisection2(RootsBisection2 const&) = delete;
|
|
RootsBisection2(RootsBisection2&&) = delete;
|
|
RootsBisection2& operator=(RootsBisection2 const&) = delete;
|
|
RootsBisection2& operator=(RootsBisection2&&) = delete;
|
|
|
|
uint32_t operator()(
|
|
std::function<Real(Real const&, Real const&)> F,
|
|
std::function<Real(Real const&, Real const&)> G,
|
|
Real const& xMin, Real const& xMax, Real const& yMin, Real const& yMax,
|
|
Real& xRoot, Real& yRoot, Real& fAtRoot, Real& gAtRoot)
|
|
{
|
|
// XFunction(x) = F(x,y), where G(x,y) = 0.
|
|
auto XFunction = [this, &F, &G, &yMin, &yMax](Real const& x)
|
|
{
|
|
// YFunction(y) = G(x,y)
|
|
auto YFunction = [this, &G, &x](Real const& y)
|
|
{
|
|
return G(x, y);
|
|
};
|
|
|
|
// Bisect in the y-variable to find the root of YFunction(y).
|
|
uint32_t numYIterations = mYBisector(YFunction, yMin, yMax, mYRoot, mGAtRoot);
|
|
if (numYIterations == 0)
|
|
{
|
|
// The interval is not guaranteed to bound a root.
|
|
std::ostringstream message;
|
|
message << std::setprecision(20)
|
|
<< "yMin = " << (double)yMin
|
|
<< ", yMax = " << (double)yMax
|
|
<< ", fMin = " << (double)YFunction(yMin)
|
|
<< ", fMax = " << (double)YFunction(yMax)
|
|
<< std::endl;
|
|
LogWarning(message.str());
|
|
|
|
}
|
|
return F(x, mYRoot);
|
|
};
|
|
|
|
// Bisect in the x-variable to find the root of XFunction(x).
|
|
uint32_t numXIterations = mXBisector(XFunction, xMin, xMax, mXRoot, mFAtRoot);
|
|
if (numXIterations == 0)
|
|
{
|
|
// The interval is not guaranteed to bound a root.
|
|
std::ostringstream message;
|
|
message << std::setprecision(20)
|
|
<< "xMin = " << (double)xMin
|
|
<< ", xMax = " << (double)xMax
|
|
<< ", fMin = " << (double)XFunction(xMin)
|
|
<< ", fMax = " << (double)XFunction(xMax)
|
|
<< std::endl;
|
|
LogWarning(message.str());
|
|
|
|
}
|
|
|
|
xRoot = mXRoot;
|
|
yRoot = mYRoot;
|
|
fAtRoot = mFAtRoot;
|
|
gAtRoot = mGAtRoot;
|
|
return numXIterations;
|
|
}
|
|
|
|
private:
|
|
RootsBisection1<Real> mXBisector, mYBisector;
|
|
Real mXRoot, mYRoot, mFAtRoot, mGAtRoot;
|
|
};
|
|
}
|
|
|