Point¶
- 二次元座標を表すクラスと、便利な関数・演算子オーバーロードを実装する。
Point.hpp
#pragma once
#include <cmath> // std::sqrt
#include <iostream> // std::ostream, std::istream
#include <format> // std::formatter
#include "Common.hpp"
namespace seccamp
{
/// @brief 二次元座標
struct Point
{
/// @brief X 成分
int32 x;
/// @brief Y 成分
int32 y;
/// @brief デフォルトコンストラクタ
[[nodiscard]]
Point() = default;
/// @brief 二次元座標を作成します。
/// @param _x X 成分
/// @param _y Y 成分
[[nodiscard]]
constexpr Point(int32 _x, int32 _y) noexcept
: x{ _x }
, y{ _y } {}
/// @brief 2 つの二次元座標が等しいかを返します。
/// @param lhs 一方の二次元座標
/// @param rhs もう一方の二次元座標
/// @return 2 つの二次元座標が等しい場合 true, それ以外の場合は false
[[nodiscard]]
friend constexpr bool operator ==(const Point& lhs, const Point& rhs) noexcept = default;
[[nodiscard]]
constexpr Point operator +() const noexcept
{
return *this;
}
[[nodiscard]]
constexpr Point operator +(const Point& p) const noexcept
{
return{ (x + p.x), (y + p.y) };
}
[[nodiscard]]
constexpr Point operator -() const noexcept
{
return{ -x, -y };
}
[[nodiscard]]
constexpr Point operator -(const Point& p) const noexcept
{
return{ (x - p.x), (y - p.y) };
}
[[nodiscard]]
constexpr Point operator *(int32 s) const noexcept
{
return{ (x * s), (y * s) };
}
[[nodiscard]]
friend constexpr Point operator *(int32 s, const Point& p) noexcept
{
return{ (s * p.x), (s * p.y) };
}
[[nodiscard]]
constexpr Point operator /(int32 s) const noexcept
{
return{ (x / s), (y / s) };
}
[[nodiscard]]
constexpr Point operator %(int32 s) const noexcept
{
return{ (x % s), (y % s) };
}
[[nodiscard]]
constexpr Point operator %(const Point& p) const noexcept
{
return{ (x % p.x), (y % p.y) };
}
constexpr Point& operator +=(const Point& p) noexcept
{
x += p.x;
y += p.y;
return *this;
}
constexpr Point& operator -=(const Point& p) noexcept
{
x -= p.x;
y -= p.y;
return *this;
}
constexpr Point& operator *=(int32 s) noexcept
{
x *= s;
y *= s;
return *this;
}
constexpr Point& operator /=(int32 s) noexcept
{
x /= s;
y /= s;
return *this;
}
constexpr Point& operator %=(int32 s) noexcept
{
x %= s;
y %= s;
return *this;
}
/// @brief 成分がすべて 0 であるかを返します。
/// @return 成分がすべて 0 である場合 true, それ以外の場合は false
[[nodiscard]]
constexpr bool isZero() const noexcept
{
return ((x == 0) && (y == 0));
}
/// @brief 成分をすべて 0 にします。
constexpr void clear() noexcept
{
x = 0;
y = 0;
}
/// @brief 成分を設定します。
/// @param _x 新しい X 成分
/// @param _y 新しい Y 成分
/// @return *this
constexpr Point& set(int32 _x, int32 _y) noexcept
{
x = _x;
y = _y;
return *this;
}
/// @brief 成分を設定します。
/// @param p 新しい成分
/// @return *this
constexpr Point& set(const Point& p) noexcept
{
x = p.x;
y = p.y;
return *this;
}
/// @brief 原点からの距離を返します。
/// @tparam Type 距離の型
/// @return 原点からの距離
template <class Type = double>
[[nodiscard]]
Type length() const noexcept
{
return std::sqrt(lengthSq<Type>());
}
/// @brief 原点からの距離の 2 乗を返します。
/// @tparam Type 距離の型
/// @return 原点からの距離の 2 乗
template <class Type = double>
[[nodiscard]]
constexpr Type lengthSq() const noexcept
{
const Type x_ = static_cast<Type>(x);
const Type y_ = static_cast<Type>(y);
return ((x_ * x_) + (y_ * y_));
}
/// @brief 原点からのマンハッタン距離を返します。
/// @return 原点からのマンハッタン距離
[[nodiscard]]
constexpr int64 manhattanDistance() const noexcept
{
const int64 x_ = (x < 0) ? -x : x;
const int64 y_ = (y < 0) ? -y : y;
return (x_ + y_);
}
/// @brief { x, x } を返します。
/// @return { x, x }
[[nodiscard]]
constexpr Point xx() const noexcept
{
return{ x, x };
}
/// @brief { y, y } を返します。
/// @return { y, y }
[[nodiscard]]
constexpr Point yy() const noexcept
{
return{ y, y };
}
/// @brief { x, y } を返します。
/// @return { x, y }
[[nodiscard]]
constexpr Point xy() const noexcept
{
return *this;
}
/// @brief { y, x } を返します。
/// @return { y, x }
[[nodiscard]]
constexpr Point yx() const noexcept
{
return{ y, x };
}
/// @brief { x, 0 } を返します。
/// @return { x, 0 }
[[nodiscard]]
constexpr Point x0() const noexcept
{
return{ x, 0 };
}
/// @brief { 0, y } を返します。
/// @return { 0, y }
[[nodiscard]]
constexpr Point y0() const noexcept
{
return{ y, 0 };
}
/// @brief { 0, 0 } を返します。
/// @return { 0, 0 }
[[nodiscard]]
static constexpr Point Zero() noexcept
{
return{ 0, 0 };
}
/// @brief { 1, 1 } を返します。
/// @return { 1, 1 }
[[nodiscard]]
static constexpr Point One() noexcept
{
return{ 1, 1 };
}
/// @brief { 1, 0 } を返します。
/// @return { 1, 0 }
[[nodiscard]]
static constexpr Point UnitX() noexcept
{
return{ 1, 0 };
}
/// @brief { 0, 1 } を返します。
/// @return { 0, 1 }
[[nodiscard]]
static constexpr Point UnitY() noexcept
{
return{ 0, 1 };
}
/// @brief { value, value } を返します。
/// @param value 成分の値
/// @return { value, value }
[[nodiscard]]
static constexpr Point All(int32 value = 1) noexcept
{
return{ value, value };
}
/// @brief 出力ストリームに書き込みます。
/// @param os 出力ストリーム
/// @param p 書き込む値
/// @return 出力ストリーム
friend std::ostream& operator <<(std::ostream& os, const Point& p)
{
return os << '(' << p.x << ", " << p.y << ')';
}
/// @brief 入力ストリームから読み込みます。
/// @param is 入力ストリーム
/// @param p 読み込んだ値の格納先
/// @return 入力ストリーム
friend std::istream& operator >>(std::istream& is, Point& p)
{
char t;
return is >> t >> p.x >> t >> p.y >> t;
}
};
using Size = Point;
}
/// @brief Point 型を std::format に対応させるための std::formatter 特殊化
template<>
struct std::formatter<seccamp::Point>
{
template <class ParseContext>
constexpr auto parse(ParseContext& ctx)
{
return ctx.begin();
}
template <class FormtContext>
auto format(const seccamp::Point& p, FormtContext& ctx) const
{
return std::format_to(ctx.out(), "({}, {})", p.x, p.y);
}
};