0

I am using the boost geometry library to compare two different polygons. Specifically, I am using the equals algorithm to see if two polygons are congruent (equal dimensions).

The problem is that the tolerance on the algorithm is too tight and two polygons that should be congruent (after some floating point operations) are not within the tolerance defined by the algorithm.

I'm almost certain that the library is using std::numeric_limits<double>::epsilon() (~2.22e-16) to establish the tolerance. I would like to set the tolerance to be larger (say 1.0e-10).

Any ideas on how to do this?

EDIT: I've changed the title to reflect the responses in the comments. Please respond to the follow-up below:

Is it possible to override just the boost::geometry::math::detail::equals<Type,true>::apply function?

This way I could replace only the code where the floating point comparison occurs and I wouldn't have to rewrite a majority of the boost::geometry::equals algorithm.

For reference, here is the current code from the boost library:

template <typename Type, bool IsFloatingPoint>
struct equals
{
    static inline bool apply(Type const& a, Type const& b)
    {
        return a == b;
    }
};

template <typename Type>
struct equals<Type, true>
{
    static inline Type get_max(Type const& a, Type const& b, Type const& c)
    {
        return (std::max)((std::max)(a, b), c);
    }

    static inline bool apply(Type const& a, Type const& b)
    {
        if (a == b)
        {
            return true;
        }

        // See http://www.parashift.com/c++-faq-lite/newbie.html#faq-29.17,
        // FUTURE: replace by some boost tool or boost::test::close_at_tolerance
        return std::abs(a - b) <= std::numeric_limits<Type>::epsilon() * get_max(std::abs(a), std::abs(b), 1.0);
    }
};
Neal Kruis
  • 2,055
  • 3
  • 26
  • 49
  • 1
    A solution probably involves writing a custom `equals` algorithm. It almost certainly does *not* involve “How to override value of std::numeric_limits::epsilon()”. Even if you could do that you wouldn’t want to. – Cheers and hth. - Alf Aug 04 '14 at 21:54
  • 3
    `numeric_limits::epsilon` has a very specific, well-defined meaning. You can't redefine it any more than you can redefine the value of "two". – Kerrek SB Aug 04 '14 at 22:03
  • Ok. So does this seem like a shortcoming of the `equals` algorithm to others? Maybe the best approach would be to have an optional tolerance argument that can be passed by the user? In the meantime I suppose I'll have to perform a different workaround. – Neal Kruis Aug 04 '14 at 22:07
  • 2
    Yeah, it's actually something I complained about during the review of Boost.Geometry. There is no avenue for dealing with tolerances or floating point comparisons. That said it shouldn't be too hard to define your own. – Brandon Kohn Aug 04 '14 at 22:41
  • All, I've changed my question to reflect your point about not re-defining an existing value. – Neal Kruis Aug 05 '14 at 21:53

1 Answers1

1

The mentioned code can be found in boost/geometry/util/math.hpp, currently in Boost 1.56 or older (here on GitHub).

There is a free function boost::geometry::math::equals() calling internally boost::geometry::math::detail::equals<>::apply(). So to change the default behavior you could overload this function or specialize the struct for some coordinate type or types. Have in mind that in some algorithms that type may be promoted to some more precise type.

Of course you could also use your own, non-standard coordinate type and implement required operators or overload the function mentioned above.

But... you might consider describing a specific case when you think that the calculated result is wrong to be sure that this question is not a XY problem. Playing with epsilon might improve the result in some cases but make things worse in other. What if some parts of the algorithm not related to the comparison might be improved? Then it would be helpful if you wrote which version of Boost.Geometry you're using, the compiler, etc.

Community
  • 1
  • 1
Adam Wulkiewicz
  • 2,068
  • 18
  • 24