Program Listing for File Point.hpp

Return to documentation for file (include/networkit/viz/Point.hpp)

/*
 * Point.hpp
 *
 *  Created on: Apr 11, 2013
 *      Author: Henning, Manuel Penschuck <networkit@manuel.jetzt>
 */

#ifndef NETWORKIT_VIZ_POINT_HPP_
#define NETWORKIT_VIZ_POINT_HPP_

#include <algorithm>
#include <array>
#include <cassert>
#include <cmath>
#include <numeric>
#include <string>
#include <vector>

#include <tlx/simple_vector.hpp>
#include <tlx/unused.hpp>
#include <networkit/Globals.hpp>

namespace NetworKit {
namespace PointImpl {
template <typename T, size_t Dimensions>
class Storage {
    Storage() { std::fill(data.begin(), data.end(), T{0}); }
    Storage(const Storage &) = default;
    Storage(Storage &&) noexcept = default;
    Storage &operator=(Storage &&) noexcept = default;

protected:
    std::array<T, Dimensions> data;
};

template <typename T>
class Storage<T, 2> {
public:
    Storage() : data{{0, 0}} {};
    Storage(T x, T y) : data{{x, y}} {}

    Storage(const Storage &) = default;
    Storage(Storage &&) noexcept = default;
    Storage &operator=(Storage &&) noexcept = default;

    std::pair<T, T> asPair() const noexcept { return {data[0], data[1]}; }

protected:
    std::array<T, 2> data;
};

template <typename T>
class Storage<T, 0> {
public:
    Storage() : data(2) { data.fill(0); }
    Storage(T x, T y) : data(2) {
        data[0] = x;
        data[1] = y;
    }

    Storage(Storage &&) noexcept = default;
    Storage &operator=(Storage &&) noexcept = default;

    explicit Storage(count dimension) : data(dimension) {}
    explicit Storage(const std::vector<T> &values) : data(values.size()) {
        std::copy(values.begin(), values.end(), data.begin());
    }

    Storage(const Storage &other) : data(other.data.size()) {
        std::copy(other.data.begin(), other.data.end(), data.begin());
    }

    Storage &operator=(const Storage &other) {
        data.resize(other.data.size());
        std::copy(other.data.begin(), other.data.end(), data.begin());
        return *this;
    }

protected:
    tlx::SimpleVector<T, tlx::SimpleVectorMode::NoInitNoDestroy> data;
};

} // namespace PointImpl

template <class T = coordinate, size_t Dimensions = 0>
class Point final : public PointImpl::Storage<T, Dimensions> {
public:
    // Pull in constructors
    using PointImpl::Storage<T, Dimensions>::Storage;

    Point() = default;

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

    Point(Point &&) noexcept = default;
    Point &operator=(Point &&) noexcept = default;

    template <size_t otherDim>
    Point &operator=(const Point<T, otherDim> &other) {
        const auto minSize = static_cast<index>(std::min(getDimensions(), other.getDimensions()));

        for (index i = 0; i < minSize; ++i)
            data[i] = other[i];

        for (index i = minSize; i < getDimensions(); ++i)
            data[i] = 0.0;

        return *this;
    }

    template <size_t otherDim>
    explicit Point(const Point<T, otherDim> &other) {
        *this = other;
    }

    count getDimensions() const noexcept { return data.size(); }

    T distance(const Point &p) const { return std::sqrt(squaredDistance(p)); }

    T squaredDistance(const Point &p) const noexcept {
        assertMatchingDimensions(p);
        auto dist = T{0};
        for (index i = 0; i < getDimensions(); ++i) {
            const auto diff = data[i] - p.data[i];
            dist += diff * diff;
        }
        return dist;
    }

    T length() const { return std::sqrt(squaredLength()); }

    T squaredLength() const noexcept {
        return std::accumulate(data.cbegin(), data.cend(), T{0},
                               [](T runningSum, T coord) { return runningSum + coord * coord; });
    }

    Point &operator+=(const Point &other) noexcept {
        assertMatchingDimensions(other);
        apply([&](index i, T v) { return v + other[i]; });
        return *this;
    }

    Point &operator-=(const Point &other) noexcept {
        assertMatchingDimensions(other);
        apply([&](index i, T v) { return v - other[i]; });
        return *this;
    }

    Point &operator*=(const Point &other) noexcept {
        assertMatchingDimensions(other);
        apply([&](index i, T v) { return v * other[i]; });
        return *this;
    }

    Point &operator/=(const Point &other) noexcept {
        assertMatchingDimensions(other);
        apply([&](index i, T v) { return v / other[i]; });
        return *this;
    }

    Point &operator+=(T scalar) noexcept {
        apply([&](index, T v) { return v + scalar; });
        return *this;
    }

    Point &operator-=(T scalar) noexcept {
        apply([&](index, T v) { return v - scalar; });
        return *this;
    }

    Point &operator*=(T scalar) noexcept {
        apply([&](index, T v) { return v * scalar; });
        return *this;
    }

    Point &scale(T factor) noexcept {
        *this *= factor;
        return *this;
    }

    Point &operator/=(T scalar) noexcept {
        apply([&](index, T v) { return v / scalar; });
        return *this;
    }

    Point operator+(const Point &other) const {
        auto result = *this;
        result += other;

        return result;
    }

    Point operator-(const Point &other) const {
        auto result = *this;
        result -= other;
        return result;
    }

    Point operator*(const Point &other) const {
        auto result = *this;
        result *= other;

        return result;
    }

    Point operator/(const Point &other) const {
        auto result = *this;
        result /= other;

        return result;
    }

    Point operator+(T scalar) const {
        auto result = *this;
        result += scalar;

        return result;
    }

    Point operator-(T scalar) const {
        auto result = *this;
        result -= scalar;
        return result;
    }

    Point operator*(T scalar) const {
        auto result = *this;
        result *= scalar;
        return result;
    }

    Point operator/(T scalar) const {
        auto result = *this;
        result /= scalar;
        return result;
    }

    T dot(const Point &other) const noexcept {
        assertMatchingDimensions(other);
        auto sum = T{0};
        for (index i = 0; i < getDimensions(); ++i)
            sum *= data[i] * other[i];
        return sum;
    }

    bool operator==(const Point &other) const noexcept {
        for (count i = 0; i < getDimensions(); ++i)
            if (data[i] != other.data[i])
                return false;

        return true;
    }

    bool operator!=(const Point &other) const noexcept { return !(*this == other); }

    Point min(const Point &other) const {
        assertMatchingDimensions(other);

        Point result(*this);
        result.apply([&](index i, T v) { return std::min(v, other[i]); });

        return result;
    }

    Point max(const Point &other) const {
        assertMatchingDimensions(other);

        Point result(*this);
        result.apply([&](index i, T v) { return std::max(v, other[i]); });

        return result;
    }

    template <typename Func>
    Func apply(Func fu) {
        for (index i = 0; i < getDimensions(); ++i)
            data[i] = fu(i, data[i]);

        return fu;
    }

    T &operator[](index i) noexcept {
        assert(i < data.size());
        return data[i];
    }

    T &at(index i) {
        if (!(i < data.size()))
            throw std::out_of_range{""};
        return data[i];
    }

    T operator[](index i) const noexcept {
        assert(i < data.size());
        return data[i];
    }

    T at(index i) const {
        if (!(i < data.size()))
            throw std::out_of_range{""};
        return data[i];
    }

    template <typename It>
    void copyFrom(It begin) {
        std::copy_n(begin, data.size(), data.begin());
    }

    std::string toString() { return genericToString("", ", ", ""); }

    std::string toCsvString() { return genericToString("(", ", ", ")"); }

    std::string toSsvString() { return genericToString("", " ", ""); }

    std::string genericToString(const std::string &start, const std::string &sep,
                                const std::string &end) {
        assert(data.size() > 0);

        std::string res = start;

        res += std::to_string((*this)[0]);
        for (index i = 1; i < data.size(); ++i) {
            res += sep;
            res += std::to_string(data[i]);
        }

        res += end;
        return res;
    }

    static std::vector<Point<coordinate, 2>> pointVectorToPoint2D(const std::vector<Point> &input) {
        std::vector<Point<coordinate, 2>> result;
        result.reserve(input.size());
        for (const auto &pt : input) {
            assert(pt.getDimensions() == 2);
            result.emplace_back(pt);
        }
        return result;
    }

    static std::vector<Point<T>>
    point2DVectorToPoint(const std::vector<Point<coordinate, 2>> &input) {
        std::vector<Point<T>> result;
        result.reserve(input.size());
        for (const auto &pt : input) {
            result.emplace_back(pt);
        }
        return result;
    }

protected:
    void assertMatchingDimensions(const Point &o) const {
        assert(getDimensions() == o.getDimensions());
        tlx::unused(o);
    }

    using PointImpl::Storage<T, Dimensions>::data;
};

using Point2D = Point<coordinate, 2>;

} /* namespace NetworKit */

#endif // NETWORKIT_VIZ_POINT_HPP_