mirror of
https://github.com/BlackMATov/vmath.hpp.git
synced 2025-12-15 04:35:25 +07:00
normalize axis in rotate function, little style fixes
This commit is contained in:
@@ -213,25 +213,26 @@ namespace vmath_hpp
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] mat<T, 4> rotate(T angle, const vec<T, 3>& axis) {
|
||||
const T x = axis.x;
|
||||
const T y = axis.y;
|
||||
const T z = axis.z;
|
||||
const T px = x * x;
|
||||
const T py = y * y;
|
||||
const T pz = z * z;
|
||||
const T cs = cos(angle);
|
||||
const T sn = sin(angle);
|
||||
const T ics = T(1) - cs;
|
||||
const T xym = x * y * ics;
|
||||
const T xzm = x * z * ics;
|
||||
const T yzm = y * z * ics;
|
||||
const T xsn = x * sn;
|
||||
const T ysn = y * sn;
|
||||
const T zsn = z * sn;
|
||||
const auto [s, c] = sincos(angle);
|
||||
const auto [x, y, z] = normalize(axis);
|
||||
|
||||
const T xx = x * x;
|
||||
const T yy = y * y;
|
||||
const T zz = z * z;
|
||||
|
||||
const T xs = x * s;
|
||||
const T ys = y * s;
|
||||
const T zs = z * s;
|
||||
|
||||
const T ic = T(1) - c;
|
||||
const T xym = x * y * ic;
|
||||
const T xzm = x * z * ic;
|
||||
const T yzm = y * z * ic;
|
||||
|
||||
return {
|
||||
px * ics + cs, xym + zsn, xzm - ysn, 0,
|
||||
xym - zsn, py * ics + cs, yzm + xsn, 0,
|
||||
xzm + ysn, yzm - xsn, pz * ics + cs, 0,
|
||||
xx * ic + c, xym + zs, xzm - ys, 0,
|
||||
xym - zs, yy * ic + c, yzm + xs, 0,
|
||||
xzm + ys, yzm - xs, zz * ic + c, 0,
|
||||
0, 0, 0, 1};
|
||||
}
|
||||
|
||||
@@ -242,12 +243,11 @@ namespace vmath_hpp
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] mat<T, 4> rotate_x(T angle) {
|
||||
const T cs = cos(angle);
|
||||
const T sn = sin(angle);
|
||||
const auto [s, c] = sincos(angle);
|
||||
return {
|
||||
1, 0, 0, 0,
|
||||
0, cs, sn, 0,
|
||||
0, -sn, cs, 0,
|
||||
0, c, s, 0,
|
||||
0, -s, c, 0,
|
||||
0, 0, 0, 1};
|
||||
}
|
||||
|
||||
@@ -258,12 +258,11 @@ namespace vmath_hpp
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] mat<T, 4> rotate_y(T angle) {
|
||||
const T cs = cos(angle);
|
||||
const T sn = sin(angle);
|
||||
const auto [s, c] = sincos(angle);
|
||||
return {
|
||||
cs, 0, -sn, 0,
|
||||
c, 0, -s, 0,
|
||||
0, 1, 0, 0,
|
||||
sn, 0, cs, 0,
|
||||
s, 0, c, 0,
|
||||
0, 0, 0, 1};
|
||||
}
|
||||
|
||||
@@ -274,11 +273,10 @@ namespace vmath_hpp
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] mat<T, 4> rotate_z(T angle) {
|
||||
const T cs = cos(angle);
|
||||
const T sn = sin(angle);
|
||||
const auto [s, c] = sincos(angle);
|
||||
return {
|
||||
cs, sn, 0, 0,
|
||||
-sn, cs, 0, 0,
|
||||
c, s, 0, 0,
|
||||
-s, c, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1};
|
||||
}
|
||||
@@ -321,9 +319,11 @@ namespace vmath_hpp
|
||||
const vec<T, 3> az = normalize(at - eye);
|
||||
const vec<T, 3> ax = normalize(cross(up, az));
|
||||
const vec<T, 3> ay = cross(az, ax);
|
||||
|
||||
const T dx = dot(ax, eye);
|
||||
const T dy = dot(ay, eye);
|
||||
const T dz = dot(az, eye);
|
||||
|
||||
return {
|
||||
ax.x, ay.x, az.x, 0,
|
||||
ax.y, ay.y, az.y, 0,
|
||||
@@ -336,9 +336,11 @@ namespace vmath_hpp
|
||||
const vec<T, 3> az = normalize(eye - at);
|
||||
const vec<T, 3> ax = normalize(cross(up, az));
|
||||
const vec<T, 3> ay = cross(az, ax);
|
||||
|
||||
const T dx = dot(ax, eye);
|
||||
const T dy = dot(ay, eye);
|
||||
const T dz = dot(az, eye);
|
||||
|
||||
return {
|
||||
ax.x, ay.x, az.x, 0,
|
||||
ax.y, ay.y, az.y, 0,
|
||||
@@ -382,11 +384,10 @@ namespace vmath_hpp
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] mat<T, 3> rotate(T angle) {
|
||||
const T cs = cos(angle);
|
||||
const T sn = sin(angle);
|
||||
const auto [s, c] = sincos(angle);
|
||||
return {
|
||||
cs, sn, 0,
|
||||
-sn, cs, 0,
|
||||
c, s, 0,
|
||||
-s, c, 0,
|
||||
0, 0, 1};
|
||||
}
|
||||
|
||||
@@ -482,9 +483,9 @@ namespace vmath_hpp
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] mat<T, 4> orthographic_lh_zo(T left, T right, T bottom, T top, T znear, T zfar) {
|
||||
const T sx = T(2) / (right - left);
|
||||
const T sy = T(2) / (top - bottom);
|
||||
const T sz = T(1) / (zfar - znear);
|
||||
const T sx = T(2) * reciprocal(right - left);
|
||||
const T sy = T(2) * reciprocal(top - bottom);
|
||||
const T sz = T(1) * reciprocal(zfar - znear);
|
||||
|
||||
const T tx = - (right + left) / (right - left);
|
||||
const T ty = - (top + bottom) / (top - bottom);
|
||||
@@ -499,9 +500,9 @@ namespace vmath_hpp
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] mat<T, 4> orthographic_lh_no(T left, T right, T bottom, T top, T znear, T zfar) {
|
||||
const T sx = T(2) / (right - left);
|
||||
const T sy = T(2) / (top - bottom);
|
||||
const T sz = T(2) / (zfar - znear);
|
||||
const T sx = T(2) * reciprocal(right - left);
|
||||
const T sy = T(2) * reciprocal(top - bottom);
|
||||
const T sz = T(2) * reciprocal(zfar - znear);
|
||||
|
||||
const T tx = - (right + left) / (right - left);
|
||||
const T ty = - (top + bottom) / (top - bottom);
|
||||
@@ -516,9 +517,9 @@ namespace vmath_hpp
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] mat<T, 4> orthographic_rh_zo(T left, T right, T bottom, T top, T znear, T zfar) {
|
||||
const T sx = T(2) / (right - left);
|
||||
const T sy = T(2) / (top - bottom);
|
||||
const T sz = -T(1) / (zfar - znear);
|
||||
const T sx = T(2) * reciprocal(right - left);
|
||||
const T sy = T(2) * reciprocal(top - bottom);
|
||||
const T sz = -T(1) * reciprocal(zfar - znear);
|
||||
|
||||
const T tx = - (right + left) / (right - left);
|
||||
const T ty = - (top + bottom) / (top - bottom);
|
||||
@@ -533,9 +534,9 @@ namespace vmath_hpp
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] mat<T, 4> orthographic_rh_no(T left, T right, T bottom, T top, T znear, T zfar) {
|
||||
const T sx = T(2) / (right - left);
|
||||
const T sy = T(2) / (top - bottom);
|
||||
const T sz = -T(2) / (zfar - znear);
|
||||
const T sx = T(2) * reciprocal(right - left);
|
||||
const T sy = T(2) * reciprocal(top - bottom);
|
||||
const T sz = -T(2) * reciprocal(zfar - znear);
|
||||
|
||||
const T tx = - (right + left) / (right - left);
|
||||
const T ty = - (top + bottom) / (top - bottom);
|
||||
@@ -552,7 +553,7 @@ namespace vmath_hpp
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] mat<T, 4> perspective_lh_zo(T fov, T aspect, T znear, T zfar) {
|
||||
const T sy = T(1) / tan(fov * T(0.5));
|
||||
const T sy = reciprocal(tan(fov * T(0.5)));
|
||||
const T sx = sy / aspect;
|
||||
const T sz = zfar / (zfar - znear);
|
||||
const T tz = (znear * zfar) / (znear - zfar);
|
||||
@@ -565,7 +566,7 @@ namespace vmath_hpp
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] mat<T, 4> perspective_lh_no(T fov, T aspect, T znear, T zfar) {
|
||||
const T sy = T(1) / tan(fov * T(0.5));
|
||||
const T sy = reciprocal(tan(fov * T(0.5)));
|
||||
const T sx = sy / aspect;
|
||||
const T sz = (zfar + znear) / (zfar - znear);
|
||||
const T tz = (T(2) * znear * zfar) / (znear - zfar);
|
||||
@@ -578,7 +579,7 @@ namespace vmath_hpp
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] mat<T, 4> perspective_rh_zo(T fov, T aspect, T znear, T zfar) {
|
||||
const T sy = T(1) / tan(fov * T(0.5));
|
||||
const T sy = reciprocal(tan(fov * T(0.5)));
|
||||
const T sx = sy / aspect;
|
||||
const T sz = zfar / (znear - zfar);
|
||||
const T tz = (znear * zfar) / (znear - zfar);
|
||||
@@ -591,7 +592,7 @@ namespace vmath_hpp
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] mat<T, 4> perspective_rh_no(T fov, T aspect, T znear, T zfar) {
|
||||
const T sy = T(1) / tan(fov * T(0.5));
|
||||
const T sy = reciprocal(tan(fov * T(0.5)));
|
||||
const T sx = sy / aspect;
|
||||
const T sz = (zfar + znear) / (znear - zfar);
|
||||
const T tz = (T(2) * znear * zfar) / (znear - zfar);
|
||||
@@ -620,11 +621,10 @@ namespace vmath_hpp
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] vec<T, 2> rotate(const vec<T, 2>& v, T angle) {
|
||||
const T cs = cos(angle);
|
||||
const T sn = sin(angle);
|
||||
const auto [s, c] = sincos(angle);
|
||||
return {
|
||||
v.x * cs - v.y * sn,
|
||||
v.x * sn + v.y * cs};
|
||||
v.x * c - v.y * s,
|
||||
v.x * s + v.y * c};
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
|
||||
@@ -8,6 +8,158 @@
|
||||
|
||||
#include "vmath_fwd.hpp"
|
||||
|
||||
//
|
||||
// Common Functions
|
||||
//
|
||||
|
||||
namespace vmath_hpp
|
||||
{
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_unsigned_v<T>, T>
|
||||
constexpr abs(T x) noexcept {
|
||||
return x;
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_signed_v<T>, T>
|
||||
constexpr abs(T x) noexcept {
|
||||
return x >= T(0) ? x : -x;
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, T>
|
||||
constexpr sign(T x) noexcept {
|
||||
return static_cast<T>((T(0) < x) - (x < T(0)));
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
|
||||
constexpr reciprocal(T x) noexcept {
|
||||
return T(1) / x;
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
|
||||
floor(T x) noexcept {
|
||||
return std::floor(x);
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
|
||||
trunc(T x) noexcept {
|
||||
return std::trunc(x);
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
|
||||
round(T x) noexcept {
|
||||
return std::round(x);
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
|
||||
ceil(T x) noexcept {
|
||||
return std::ceil(x);
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
|
||||
fract(T x) noexcept {
|
||||
return x - floor(x);
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
|
||||
fmod(T x, T y) noexcept {
|
||||
return std::fmod(x, y);
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
|
||||
modf(T x, T* y) noexcept {
|
||||
return std::modf(x, y);
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, T>
|
||||
constexpr min(T x, T y) noexcept {
|
||||
return x < y ? x : y;
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, T>
|
||||
constexpr max(T x, T y) noexcept {
|
||||
return x < y ? y : x;
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, T>
|
||||
constexpr clamp(T x, T min_x, T max_x) noexcept {
|
||||
return min(max(x, min_x), max_x);
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, T>
|
||||
constexpr saturate(T x) noexcept {
|
||||
return clamp(x, T(0), T(1));
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
|
||||
constexpr lerp(T x, T y, T a) noexcept {
|
||||
return x * (T(1) - a) + y * a;
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
|
||||
constexpr step(T edge, T x) noexcept {
|
||||
return x < edge ? T(0) : T(1);
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
|
||||
constexpr smoothstep(T edge0, T edge1, T x) noexcept {
|
||||
const T t = clamp((x - edge0) / (edge1 - edge0), T(0), T(1));
|
||||
return t * t * (T(3) - T(2) * t);
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, bool>
|
||||
isnan(T x) noexcept {
|
||||
return std::isnan(x);
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, bool>
|
||||
isinf(T x) noexcept {
|
||||
return std::isinf(x);
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, bool>
|
||||
isfinite(T x) noexcept {
|
||||
return std::isfinite(x);
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
|
||||
fma(T x, T y, T z) noexcept {
|
||||
return std::fma(x, y, z);
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
|
||||
frexp(T x, int* exp) noexcept {
|
||||
return std::frexp(x, exp);
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
|
||||
ldexp(T x, int exp) noexcept {
|
||||
return std::ldexp(x, exp);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Angle and Trigonometry Functions
|
||||
//
|
||||
@@ -163,159 +315,7 @@ namespace vmath_hpp
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
|
||||
rsqrt(T x) noexcept {
|
||||
return T(1) / sqrt(x);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Common Functions
|
||||
//
|
||||
|
||||
namespace vmath_hpp
|
||||
{
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_unsigned_v<T>, T>
|
||||
constexpr abs(T x) noexcept {
|
||||
return x;
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_signed_v<T>, T>
|
||||
constexpr abs(T x) noexcept {
|
||||
return x >= T(0) ? x : -x;
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, T>
|
||||
constexpr sign(T x) noexcept {
|
||||
return static_cast<T>((T(0) < x) - (x < T(0)));
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
|
||||
constexpr reciprocal(T x) noexcept {
|
||||
return T(1) / x;
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
|
||||
floor(T x) noexcept {
|
||||
return std::floor(x);
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
|
||||
trunc(T x) noexcept {
|
||||
return std::trunc(x);
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
|
||||
round(T x) noexcept {
|
||||
return std::round(x);
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
|
||||
ceil(T x) noexcept {
|
||||
return std::ceil(x);
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
|
||||
fract(T x) noexcept {
|
||||
return x - floor(x);
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
|
||||
fmod(T x, T y) noexcept {
|
||||
return std::fmod(x, y);
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
|
||||
modf(T x, T* y) noexcept {
|
||||
return std::modf(x, y);
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, T>
|
||||
constexpr min(T x, T y) noexcept {
|
||||
return x < y ? x : y;
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, T>
|
||||
constexpr max(T x, T y) noexcept {
|
||||
return x < y ? y : x;
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, T>
|
||||
constexpr clamp(T x, T min_x, T max_x) noexcept {
|
||||
return min(max(x, min_x), max_x);
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, T>
|
||||
constexpr saturate(T x) noexcept {
|
||||
return clamp(x, T(0), T(1));
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
|
||||
constexpr lerp(T x, T y, T a) noexcept {
|
||||
return x * (T(1) - a) + y * a;
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
|
||||
constexpr step(T edge, T x) noexcept {
|
||||
return x < edge ? T(0) : T(1);
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
|
||||
constexpr smoothstep(T edge0, T edge1, T x) noexcept {
|
||||
const T t = clamp((x - edge0) / (edge1 - edge0), T(0), T(1));
|
||||
return t * t * (T(3) - T(2) * t);
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, bool>
|
||||
isnan(T x) noexcept {
|
||||
return std::isnan(x);
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, bool>
|
||||
isinf(T x) noexcept {
|
||||
return std::isinf(x);
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, bool>
|
||||
isfinite(T x) noexcept {
|
||||
return std::isfinite(x);
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
|
||||
fma(T x, T y, T z) noexcept {
|
||||
return std::fma(x, y, z);
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
|
||||
frexp(T x, int* exp) noexcept {
|
||||
return std::frexp(x, exp);
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
[[nodiscard]] std::enable_if_t<std::is_floating_point_v<T>, T>
|
||||
ldexp(T x, int exp) noexcept {
|
||||
return std::ldexp(x, exp);
|
||||
return reciprocal(sqrt(x));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user