↰ 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_