Added epsilon constant and improved queries... still probably broken, need extra test
This commit is contained in:
parent
64da6d3da3
commit
d09501b7b0
@ -52,8 +52,12 @@ namespace glm
|
|||||||
/// @addtogroup gtx_constants
|
/// @addtogroup gtx_constants
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
|
/// @todo Implement epsilon for half-precision floating point type.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T pi();
|
GLM_FUNC_QUALIFIER T epsilon()
|
||||||
|
{
|
||||||
|
return std::numeric_limits<T>::epsilon();
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
GLM_FUNC_QUALIFIER T pi()
|
GLM_FUNC_QUALIFIER T pi()
|
||||||
|
@ -42,6 +42,7 @@
|
|||||||
// Dependency:
|
// Dependency:
|
||||||
#include "../glm.hpp"
|
#include "../glm.hpp"
|
||||||
#include "../gtx/vector_query.hpp"
|
#include "../gtx/vector_query.hpp"
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
#if(defined(GLM_MESSAGES) && !defined(glm_ext))
|
#if(defined(GLM_MESSAGES) && !defined(glm_ext))
|
||||||
# pragma message("GLM: GLM_GTX_matrix_query extension included")
|
# pragma message("GLM: GLM_GTX_matrix_query extension included")
|
||||||
@ -52,61 +53,61 @@ namespace glm
|
|||||||
/// @addtogroup gtx_matrix_query
|
/// @addtogroup gtx_matrix_query
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
//! Return if a matrix a null matrix.
|
/// Return whether a matrix a null matrix.
|
||||||
//! From GLM_GTX_matrix_query extension.
|
/// From GLM_GTX_matrix_query extension.
|
||||||
template<typename T>
|
template<typename T>
|
||||||
bool isNull(
|
bool isNull(
|
||||||
detail::tmat2x2<T> const & m,
|
detail::tmat2x2<T> const & m,
|
||||||
T const & epsilon = std::numeric_limits<T>::epsilon());
|
T const & epsilon/* = std::numeric_limits<T>::epsilon()*/);
|
||||||
|
|
||||||
//! Return if a matrix a null matrix.
|
/// Return whether a matrix a null matrix.
|
||||||
//! From GLM_GTX_matrix_query extension.
|
/// From GLM_GTX_matrix_query extension.
|
||||||
template<typename T>
|
template<typename T>
|
||||||
bool isNull(
|
bool isNull(
|
||||||
detail::tmat3x3<T> const & m,
|
detail::tmat3x3<T> const & m,
|
||||||
T const & epsilon = std::numeric_limits<T>::epsilon());
|
T const & epsilon/* = std::numeric_limits<T>::epsilon()*/);
|
||||||
|
|
||||||
//! Return if a matrix a null matrix.
|
/// Return whether a matrix is a null matrix.
|
||||||
//! From GLM_GTX_matrix_query extension.
|
/// From GLM_GTX_matrix_query extension.
|
||||||
template<typename T>
|
template<typename T>
|
||||||
bool isNull(
|
bool isNull(
|
||||||
detail::tmat4x4<T> const & m,
|
detail::tmat4x4<T> const & m,
|
||||||
T const & epsilon = std::numeric_limits<T>::epsilon());
|
T const & epsilon/* = std::numeric_limits<T>::epsilon()*/);
|
||||||
|
|
||||||
//! Return if a matrix an identity matrix.
|
/// Return whether a matrix is an identity matrix.
|
||||||
//! From GLM_GTX_matrix_query extension.
|
/// From GLM_GTX_matrix_query extension.
|
||||||
template<typename genType>
|
template<typename genType>
|
||||||
bool isIdentity(
|
bool isIdentity(
|
||||||
genType const & m,
|
genType const & m,
|
||||||
typename genType::value_type const & epsilon = std::numeric_limits<typename genType::value_type>::epsilon());
|
typename genType::value_type const & epsilon/* = std::numeric_limits<typename genType::value_type>::epsilon()*/);
|
||||||
|
|
||||||
//! Return if a matrix a normalized matrix.
|
/// Return whether a matrix is a normalized matrix.
|
||||||
//! From GLM_GTX_matrix_query extension.
|
/// From GLM_GTX_matrix_query extension.
|
||||||
template<typename T>
|
template<typename valType>
|
||||||
bool isNormalized(
|
bool isNormalized(
|
||||||
detail::tmat2x2<T> const & m,
|
detail::tmat2x2<valType> const & m,
|
||||||
T const & epsilon = std::numeric_limits<T>::epsilon());
|
valType const & epsilon/* = std::numeric_limits<valType>::epsilon()*/);
|
||||||
|
|
||||||
//! Return if a matrix a normalized matrix.
|
|
||||||
//! From GLM_GTX_matrix_query extension.
|
|
||||||
template<typename T>
|
|
||||||
bool isNormalized(
|
|
||||||
detail::tmat3x3<T> const & m,
|
|
||||||
T const & epsilon = std::numeric_limits<T>::epsilon());
|
|
||||||
|
|
||||||
//! Return if a matrix a normalized matrix.
|
|
||||||
//! From GLM_GTX_matrix_query extension.
|
|
||||||
template<typename T>
|
|
||||||
bool isNormalized(
|
|
||||||
detail::tmat4x4<T> const & m,
|
|
||||||
T const & epsilon = std::numeric_limits<T>::epsilon());
|
|
||||||
|
|
||||||
//! Return if a matrix an orthonormalized matrix.
|
/// Return whether a matrix is a normalized matrix.
|
||||||
//! From GLM_GTX_matrix_query extension.
|
/// From GLM_GTX_matrix_query extension.
|
||||||
template<typename genType>
|
template<typename valType>
|
||||||
|
bool isNormalized(
|
||||||
|
detail::tmat3x3<valType> const & m,
|
||||||
|
valType const & epsilon/* = std::numeric_limits<valType>::epsilon()*/);
|
||||||
|
|
||||||
|
/// Return whether a matrix is a normalized matrix.
|
||||||
|
/// From GLM_GTX_matrix_query extension.
|
||||||
|
template<typename valType>
|
||||||
|
bool isNormalized(
|
||||||
|
detail::tmat4x4<valType> const & m,
|
||||||
|
valType const & epsilon/* = std::numeric_limits<valType>::epsilon()*/);
|
||||||
|
|
||||||
|
/// Return whether a matrix is an orthonormalized matrix.
|
||||||
|
/// From GLM_GTX_matrix_query extension.
|
||||||
|
template<typename valType, template <typename> class matType>
|
||||||
bool isOrthogonal(
|
bool isOrthogonal(
|
||||||
genType const & m,
|
matType<valType> const & m,
|
||||||
typename genType::value_type const & epsilon = std::numeric_limits<typename genType::value_type>::epsilon());
|
valType const & epsilon/* = std::numeric_limits<genType>::epsilon()*/);
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
}//namespace glm
|
}//namespace glm
|
||||||
|
@ -70,83 +70,83 @@ namespace glm
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename genType>
|
||||||
GLM_FUNC_QUALIFIER bool isNormalized
|
GLM_FUNC_QUALIFIER bool isNormalized
|
||||||
(
|
(
|
||||||
detail::tmat2x2<T> const & m,
|
detail::tmat2x2<genType> const & m,
|
||||||
T const & epsilon
|
genType const & epsilon
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
bool result = true;
|
bool result(true);
|
||||||
for(int i = 0; result && i < 2; ++i)
|
for(detail::tmat2x2<genType>::size_type i(0); result && i < m.length(); ++i)
|
||||||
result = isNormalized(m[i], epsilon);
|
result = isNormalized(m[i], epsilon);
|
||||||
for(int i = 0; result && i < 2; ++i)
|
for(detail::tmat2x2<genType>::size_type i(0); result && i < m.length(); ++i)
|
||||||
{
|
{
|
||||||
detail::tvec2<T> v;
|
detail::tmat2x2<genType>::col_type v;
|
||||||
for(int j = 0; j < 2; ++j)
|
for(detail::tmat2x2<genType>::size_type j(0); j < m.length(); ++j)
|
||||||
v[j] = m[j][i];
|
v[j] = m[j][i];
|
||||||
result = isNormalized(v, epsilon);
|
result = isNormalized(v, epsilon);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename genType>
|
||||||
GLM_FUNC_QUALIFIER bool isNormalized
|
GLM_FUNC_QUALIFIER bool isNormalized
|
||||||
(
|
(
|
||||||
detail::tmat3x3<T> const & m,
|
detail::tmat3x3<genType> const & m,
|
||||||
T const & epsilon
|
genType const & epsilon
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
bool result = true;
|
bool result(true);
|
||||||
for(int i = 0; result && i < 3; ++i)
|
for(detail::tmat3x3<genType>::size_type i(0); result && i < m.length(); ++i)
|
||||||
result = isNormalized(m[i], epsilon);
|
result = isNormalized(m[i], epsilon);
|
||||||
for(int i = 0; result && i < 3; ++i)
|
for(detail::tmat3x3<genType>::size_type i(0); result && i < m.length(); ++i)
|
||||||
{
|
{
|
||||||
detail::tvec3<T> v;
|
detail::tmat3x3<genType>::col_type v;
|
||||||
for(int j = 0; j < 3; ++j)
|
for(detail::tmat3x3<genType>::size_type j(0); j < m.length(); ++j)
|
||||||
v[j] = m[j][i];
|
v[j] = m[j][i];
|
||||||
result = isNormalized(v, epsilon);
|
result = isNormalized(v, epsilon);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename genType>
|
||||||
GLM_FUNC_QUALIFIER bool isNormalized
|
GLM_FUNC_QUALIFIER bool isNormalized
|
||||||
(
|
(
|
||||||
detail::tmat4x4<T> const & m,
|
detail::tmat4x4<genType> const & m,
|
||||||
T const & epsilon
|
genType const & epsilon
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
bool result = true;
|
bool result(true);
|
||||||
for(int i = 0; result && i < 4; ++i)
|
for(detail::tmat4x4<genType>::size_type i(0); result && i < m.length(); ++i)
|
||||||
result = isNormalized(m[i], epsilon);
|
result = isNormalized(m[i], epsilon);
|
||||||
for(int i = 0; result && i < 4; ++i)
|
for(detail::tmat4x4<genType>::size_type i(0); result && i < m.length(); ++i)
|
||||||
{
|
{
|
||||||
detail::tvec4<T> v;
|
detail::tmat4x4<genType>::col_type v;
|
||||||
for(int j = 0; j < 4; ++j)
|
for(detail::tmat4x4<genType>::size_type j(0); j < m.length(); ++j)
|
||||||
v[j] = m[j][i];
|
v[j] = m[j][i];
|
||||||
result = isNormalized(v, epsilon);
|
result = isNormalized(v, epsilon);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename genType>
|
template<typename genType, template <typename> class matType>
|
||||||
GLM_FUNC_QUALIFIER bool isOrthogonal
|
GLM_FUNC_QUALIFIER bool isOrthogonal
|
||||||
(
|
(
|
||||||
genType const & m,
|
matType<genType> const & m,
|
||||||
typename genType::value_type const & epsilon
|
genType const & epsilon
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
bool result = true;
|
bool result(true);
|
||||||
for(int i = 0; result && i < genType::col_size() - 1; ++i)
|
for(typename matType<genType>::size_type i(0); result && i < m.length() - 1; ++i)
|
||||||
for(int j= i + 1; result && j < genType::col_size(); ++j)
|
for(typename matType<genType>::size_type j(i + 1); result && j < m.length(); ++j)
|
||||||
result = areOrthogonal(m[i], m[j], epsilon);
|
result = areOrthogonal(m[i], m[j], epsilon);
|
||||||
|
|
||||||
if(result)
|
if(result)
|
||||||
{
|
{
|
||||||
genType tmp = transpose(m);
|
matType<genType> tmp = transpose(m);
|
||||||
for(int i = 0; result && i < genType::col_size() - 1 ; ++i)
|
for(typename matType<genType>::size_type i(0); result && i < m.length() - 1 ; ++i)
|
||||||
for(int j = i + 1; result && j < genType::col_size(); ++j)
|
for(typename matType<genType>::size_type j(i + 1); result && j < m.length(); ++j)
|
||||||
result = areOrthogonal(tmp[i], tmp[j], epsilon);
|
result = areOrthogonal(tmp[i], tmp[j], epsilon);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -52,59 +52,73 @@ namespace glm
|
|||||||
/// @addtogroup gtx_vector_query
|
/// @addtogroup gtx_vector_query
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
//! Check if two vectors are collinears.
|
//! Check whether two vectors are collinears.
|
||||||
//! From GLM_GTX_vector_query extensions.
|
//! From GLM_GTX_vector_query extensions.
|
||||||
template <typename genType>
|
template <typename genType>
|
||||||
bool areCollinear(
|
bool areCollinear(
|
||||||
genType const & v0,
|
genType const & v0,
|
||||||
genType const & v1,
|
genType const & v1,
|
||||||
typename genType::value_type const & epsilon = std::numeric_limits<typename genType::value_type>::epsilon());
|
typename genType::value_type const & epsilon/* = std::numeric_limits<typename genType::value_type>::epsilon()*/);
|
||||||
|
|
||||||
//! Check if two vectors are opposites.
|
//! Check whether two vectors are opposites.
|
||||||
//! From GLM_GTX_vector_query extensions.
|
//! From GLM_GTX_vector_query extensions.
|
||||||
template <typename genType>
|
template <typename genType>
|
||||||
bool areOpposite(
|
bool areOpposite(
|
||||||
genType const & v0,
|
genType const & v0,
|
||||||
genType const & v1,
|
genType const & v1,
|
||||||
typename genType::value_type const & epsilon = std::numeric_limits<typename genType::value_type>::epsilon());
|
typename genType::value_type const & epsilon/* = std::numeric_limits<typename genType::value_type>::epsilon()*/);
|
||||||
|
|
||||||
//! Check if two vectors are orthogonals.
|
//! Check whether two vectors are orthogonals.
|
||||||
//! From GLM_GTX_vector_query extensions.
|
//! From GLM_GTX_vector_query extensions.
|
||||||
template <typename genType>
|
template <typename genType>
|
||||||
bool areOrthogonal(
|
bool areOrthogonal(
|
||||||
genType const & v0,
|
genType const & v0,
|
||||||
genType const & v1,
|
genType const & v1,
|
||||||
typename genType::value_type const & epsilon = std::numeric_limits<typename genType::value_type>::epsilon());
|
typename genType::value_type const & epsilon/* = std::numeric_limits<typename genType::value_type>::epsilon()*/);
|
||||||
|
|
||||||
//! Check if a vector is normalized.
|
//! Check whether a vector is normalized.
|
||||||
//! From GLM_GTX_vector_query extensions.
|
//! From GLM_GTX_vector_query extensions.
|
||||||
template <typename genType>
|
template <typename genType, template <typename> class vecType>
|
||||||
bool isNormalized(
|
bool isNormalized(
|
||||||
genType const & v,
|
vecType<genType> const & v,
|
||||||
typename genType::value_type const & epsilon = std::numeric_limits<typename genType::value_type>::epsilon());
|
genType const & epsilon/* = std::numeric_limits<genType>::epsilon()*/);
|
||||||
|
|
||||||
//! Check if a vector is null.
|
//! Check whether a vector is null.
|
||||||
//! From GLM_GTX_vector_query extensions.
|
//! From GLM_GTX_vector_query extensions.
|
||||||
template <typename genType>
|
template <typename valType>
|
||||||
bool isNull(
|
bool isNull(
|
||||||
genType const & v,
|
detail::tvec2<valType> const & v,
|
||||||
typename genType::value_type const & epsilon = std::numeric_limits<typename genType::value_type>::epsilon());
|
valType const & epsilon/* = std::numeric_limits<typename genType::value_type>::epsilon()*/);
|
||||||
|
|
||||||
//! Check if two vectors are orthonormal.
|
//! Check whether a vector is null.
|
||||||
|
//! From GLM_GTX_vector_query extensions.
|
||||||
|
template <typename valType>
|
||||||
|
bool isNull(
|
||||||
|
detail::tvec3<valType> const & v,
|
||||||
|
valType const & epsilon/* = std::numeric_limits<typename genType::value_type>::epsilon()*/);
|
||||||
|
|
||||||
|
//! Check whether a vector is null.
|
||||||
|
//! From GLM_GTX_vector_query extensions.
|
||||||
|
template <typename valType>
|
||||||
|
bool isNull(
|
||||||
|
detail::tvec4<valType> const & v,
|
||||||
|
valType const & epsilon/* = std::numeric_limits<typename genType::value_type>::epsilon()*/);
|
||||||
|
|
||||||
|
//! Check whether two vectors are orthonormal.
|
||||||
//! From GLM_GTX_vector_query extensions.
|
//! From GLM_GTX_vector_query extensions.
|
||||||
template <typename genType>
|
template <typename genType>
|
||||||
bool areOrthonormal(
|
bool areOrthonormal(
|
||||||
genType const & v0,
|
genType const & v0,
|
||||||
genType const & v1,
|
genType const & v1,
|
||||||
typename genType::value_type const & epsilon = std::numeric_limits<typename genType::value_type>::epsilon());
|
typename genType::value_type const & epsilon/* = std::numeric_limits<typename genType::value_type>::epsilon()*/);
|
||||||
|
|
||||||
//! Check if two vectors are similar.
|
//! Check whether two vectors are similar.
|
||||||
//! From GLM_GTX_vector_query extensions.
|
//! From GLM_GTX_vector_query extensions.
|
||||||
template <typename genType>
|
template <typename genType>
|
||||||
bool areSimilar(
|
bool areSimilar(
|
||||||
genType const & v0,
|
genType const & v0,
|
||||||
genType const & v1,
|
genType const & v1,
|
||||||
typename genType::value_type const & epsilon = std::numeric_limits<typename genType::value_type>::epsilon());
|
typename genType::value_type const & epsilon/* = std::numeric_limits<typename genType::value_type>::epsilon()*/);
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
}// namespace glm
|
}// namespace glm
|
||||||
|
@ -74,21 +74,41 @@ namespace glm
|
|||||||
length(v1)) * epsilon;
|
length(v1)) * epsilon;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename genType>
|
template <typename genType, template <typename> class vecType>
|
||||||
GLM_FUNC_QUALIFIER bool isNormalized
|
GLM_FUNC_QUALIFIER bool isNormalized
|
||||||
(
|
(
|
||||||
genType const & v,
|
vecType<genType> const & v,
|
||||||
typename genType::value_type const & epsilon
|
genType const & epsilon
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return abs(length(v) - typename genType::value_type(1)) <= typename genType::value_type(2) * epsilon;
|
return abs(length(v) - genType(1)) <= genType(2) * epsilon;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename genType>
|
template <typename valType>
|
||||||
GLM_FUNC_QUALIFIER bool isNull
|
GLM_FUNC_QUALIFIER bool isNull
|
||||||
(
|
(
|
||||||
genType const & v,
|
detail::tvec2<valType> const & v,
|
||||||
typename genType::value_type const & epsilon
|
valType const & epsilon
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return length(v) <= epsilon;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename valType>
|
||||||
|
GLM_FUNC_QUALIFIER bool isNull
|
||||||
|
(
|
||||||
|
detail::tvec3<valType> const & v,
|
||||||
|
valType const & epsilon
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return length(v) <= epsilon;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename valType>
|
||||||
|
GLM_FUNC_QUALIFIER bool isNull
|
||||||
|
(
|
||||||
|
detail::tvec4<valType> const & v,
|
||||||
|
valType const & epsilon
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return length(v) <= epsilon;
|
return length(v) <= epsilon;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
glmCreateTestGTC(gtx_bit)
|
glmCreateTestGTC(gtx_bit)
|
||||||
glmCreateTestGTC(gtx_gradient_paint)
|
glmCreateTestGTC(gtx_gradient_paint)
|
||||||
glmCreateTestGTC(gtx_integer)
|
glmCreateTestGTC(gtx_integer)
|
||||||
|
glmCreateTestGTC(gtx_matrix_query)
|
||||||
glmCreateTestGTC(gtx_noise)
|
glmCreateTestGTC(gtx_noise)
|
||||||
glmCreateTestGTC(gtx_quaternion)
|
glmCreateTestGTC(gtx_quaternion)
|
||||||
glmCreateTestGTC(gtx_random)
|
glmCreateTestGTC(gtx_random)
|
||||||
|
54
test/gtx/gtx_matrix_query.cpp
Normal file
54
test/gtx/gtx_matrix_query.cpp
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// OpenGL Mathematics Copyright (c) 2005 - 2011 G-Truc Creation (www.g-truc.net)
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Created : 2011-11-22
|
||||||
|
// Updated : 2011-11-22
|
||||||
|
// Licence : This source is under MIT licence
|
||||||
|
// File : test/gtx/matrix_query.cpp
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
#include <glm/gtx/matrix_query.hpp>
|
||||||
|
|
||||||
|
int test_isNull()
|
||||||
|
{
|
||||||
|
int Error(0);
|
||||||
|
|
||||||
|
bool TestA = glm::isNull(glm::mat4(0), 0.00001f);
|
||||||
|
Error += TestA ? 0 : 1;
|
||||||
|
|
||||||
|
return Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_isNormalized()
|
||||||
|
{
|
||||||
|
int Error(0);
|
||||||
|
|
||||||
|
bool TestA = glm::isNormalized(glm::mat4(1), 0.00001f);
|
||||||
|
Error += TestA ? 0 : 1;
|
||||||
|
|
||||||
|
return Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_isOrthogonal()
|
||||||
|
{
|
||||||
|
int Error(0);
|
||||||
|
|
||||||
|
bool TestA = glm::isOrthogonal(glm::mat4(1), 0.00001f);
|
||||||
|
Error += TestA ? 0 : 1;
|
||||||
|
|
||||||
|
return Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
int Error(0);
|
||||||
|
|
||||||
|
Error += test_isNull();
|
||||||
|
Error += test_isNormalized();
|
||||||
|
Error += test_isOrthogonal();
|
||||||
|
|
||||||
|
return Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user