https://gitlab.opengeosys.org/ogs/ogs.git
Raw File
Tip revision: 13d5b7a1d217f66c30a60fb04eaee7ff8021d0b3 authored by Dmitri Naumov on 15 March 2021, 12:24:35 UTC
[PL/DS] Fix spelling of class name.
Tip revision: 13d5b7a
TemplatePoint.h
/**
 * \file
 * \author Thomas Fischer
 * \date   2010-01-28
 * \brief  Definition of the TemplatePoint class.
 *
 * \copyright
 * Copyright (c) 2012-2021, OpenGeoSys Community (http://www.opengeosys.org)
 *            Distributed under a Modified BSD License.
 *              See accompanying file LICENSE.txt or
 *              http://www.opengeosys.org/project/license
 *
 */

#pragma once

#include "mathlib_export.h"

// STL
#include <algorithm>
#include <array>
#include <cassert>
#include <cmath>
#include <istream>
#include <iterator>
#include <utility>

namespace MathLib
{
/**
 * \ingroup GeoLib
 *
 * \brief class-template for points can be instantiated by a numeric type.
 * \tparam T the coordinate type
 */
template <typename T, std::size_t DIM = 3> class TemplatePoint
{
public:
    using FP_T = T;

    /** default constructor with zero coordinates */
    TemplatePoint();

    /** constructor - constructs a TemplatePoint object
     *
     * @param x std::array containing the coordinates of the point
     */
    explicit TemplatePoint(std::array<T, DIM> x);

    /** virtual destructor */
    virtual ~TemplatePoint() = default;

    TemplatePoint(TemplatePoint const&) = default;
    TemplatePoint& operator=(TemplatePoint const&) = default;

    /** \brief const access operator
     *  The access to the point coordinates is like the access to a field. Code example:
     * \code
     * Point<double> point (1.0, 2.0, 3.0);
     * double sqrNrm2 = point[0] * point[0] + point[1] * point[1] + point[2] + point[2];
     * \endcode
     */
    const T& operator[] (std::size_t idx) const
    {
        assert (idx < DIM);
        return _x[idx];
    }
    /** \brief access operator (see book Effektiv C++ programmieren - subsection 1.3.2 ).
     * \sa const T& operator[] (std::size_t idx) const
     */
    T& operator[] (std::size_t idx)
    {
        return const_cast<T&> (static_cast<const TemplatePoint&> (*this)[idx]);
    }

    /** returns an array containing the coordinates of the point */
    const T* getCoords () const
    {
        return _x.data();
    }

    T* getCoords() { return _x.data(); }

    /** write point coordinates into stream (used from operator<<)
     * \param os a standard output stream
     */
    virtual void write (std::ostream &os) const
    {
        std::copy(_x.cbegin(), _x.cend(), std::ostream_iterator<T>(os, " "));
    }

    /** read point coordinates into stream (used from operator>>) */
    virtual void read (std::istream &is)
    {
        std::copy(std::istream_iterator<T>(is), std::istream_iterator<T>(), _x.begin());
    }

protected:
    std::array<T, DIM> _x;
};

template <typename T, std::size_t DIM>
TemplatePoint<T,DIM>::TemplatePoint() :
    _x({{0}})
{}

template <typename T, std::size_t DIM>
TemplatePoint<T, DIM>::TemplatePoint(std::array<T, DIM> x) : _x(std::move(x))
{}

/** Equality of TemplatePoint's up to an epsilon.
 */
template <typename T, std::size_t DIM>
bool operator==(TemplatePoint<T,DIM> const& a, TemplatePoint<T,DIM> const& b)
{
    T const sqr_dist(sqrDist(a,b));
    auto const eps = std::numeric_limits<T>::epsilon();
    return (sqr_dist < eps*eps);
}

template <typename T, std::size_t DIM>
bool operator< (TemplatePoint<T,DIM> const& a, TemplatePoint<T,DIM> const& b)
{
    for (std::size_t i = 0; i < DIM; ++i)
    {
        if (a[i] > b[i]) {
            return false;
        }
        if (a[i] < b[i])
        {
            return true;
            }

        // continue with next dimension, because a[0] == b[0]
    }

    // The values in all dimenisions are equal.
    return false;
}

/**
 * Lexicographic comparison of points taking an epsilon into account.
 *
 * @param a first input point.
 * @param b second input point.
 * @param eps tolerance used in comparison of coordinates.
 *
 * @return true, if a is smaller then or equal to b according to the following
 * test \f$ |a_i - b_i| > \epsilon \cdot \min (|a_i|, |b_i|) \f$ \b and
 * \f$  |a_i - b_i| > \epsilon \f$ for all coordinates \f$ 0 \le i < \textrm{DIM} \f$.
 */
template <typename T, std::size_t DIM>
bool lessEq(TemplatePoint<T, DIM> const& a, TemplatePoint<T, DIM> const& b,
        double eps = std::numeric_limits<double>::epsilon())
{
    auto coordinateIsLargerEps = [&eps](T const u, T const v) -> bool
    {
        return std::abs(u - v) > eps * std::min(std::abs(v), std::abs(u)) &&
               std::abs(u - v) > eps;
    };

    for (std::size_t i = 0; i < DIM; ++i)
    {
        // test a relative and an absolute criterion
        if (coordinateIsLargerEps(a[i], b[i]))
        {
            return static_cast<bool>(a[i] <= b[i]);
        }
        // a[i] ~= b[i] up to an epsilon. Compare next dimension.
    }

    // all coordinates are equal up to an epsilon.
    return true;
}

/** overload the output operator for class Point */
template <typename T, std::size_t DIM>
std::ostream& operator<< (std::ostream &os, const TemplatePoint<T,DIM> &p)
{
    p.write (os);
    return os;
}

/** overload the input operator for class Point */
template <typename T, std::size_t DIM>
std::istream& operator>> (std::istream &is, TemplatePoint<T,DIM> &p)
{
    p.read (is);
    return is;
}
} // end namespace MathLib
back to top