Browse Source

Math: added planeEquation() helper.

pull/272/head
Vladimír Vondruš 8 years ago
parent
commit
49068f066d
  1. 3
      doc/changelog.dox
  2. 6
      src/Magnum/Math/Distance.h
  3. 34
      src/Magnum/Math/Test/Vector4Test.cpp
  4. 2
      src/Magnum/Math/Vector3.h
  5. 50
      src/Magnum/Math/Vector4.h

3
doc/changelog.dox

@ -76,6 +76,9 @@ See also:
- Added @ref Math::Constants::piQuarter()
- Added a convenience function @ref Math::select() as a constant
interpolation counterpart to @ref Math::lerp()
- Added a convenience function @ref Math::planeEquation() to aid with passing
passing parameters to @ref Math::Intersection::planeLine(),
@ref Math::Distance::pointPlane() and others
- Ability to convert @ref Math::BoolVector from and to external
representation

6
src/Magnum/Math/Distance.h

@ -169,8 +169,8 @@ The distance is negative if the point lies behind the plane.
More efficient than @ref pointPlane() when merely the sign of the distance is
of interest, for example when testing on which half space of the plane the
point lies.
@see @ref pointPlaneNormalized()
*/
@see @ref planeEquation(), @ref pointPlaneNormalized()
*/
template<class T> inline T pointPlaneScaled(const Vector3<T>& point, const Vector4<T>& plane) {
return dot(plane.xyz(), point) + plane.w();
}
@ -187,6 +187,7 @@ The distance is negative if the point lies behind the plane.
In cases where the planes normal is a unit vector, @ref pointPlaneNormalized()
is more efficient. If merely the sign of the distance is of interest,
@ref pointPlaneScaled() is more efficient.
@see @ref planeEquation()
*/
template<class T> inline T pointPlane(const Vector3<T>& point, const Vector4<T>& plane) {
return pointPlaneScaled<T>(point, plane)/plane.xyz().length();
@ -205,6 +206,7 @@ The distance is negative if the point lies behind the plane. Expects that
More efficient than @ref pointPlane() in cases where the plane's normal is
normalized. Equivalent to @ref pointPlaneScaled() but with assertion added on
top.
@see @ref planeEquation()
*/
template<class T> inline T pointPlaneNormalized(const Vector3<T>& point, const Vector4<T>& plane) {
CORRADE_ASSERT(plane.xyz().isNormalized(),

34
src/Magnum/Math/Test/Vector4Test.cpp

@ -68,6 +68,9 @@ struct Vector4Test: Corrade::TestSuite::Tester {
void threeComponent();
void twoComponent();
void planeEquationThreePoints();
void planeEquationNormalPoint();
void swizzleType();
void debug();
void configuration();
@ -93,6 +96,9 @@ Vector4Test::Vector4Test() {
&Vector4Test::threeComponent,
&Vector4Test::twoComponent,
&Vector4Test::planeEquationThreePoints,
&Vector4Test::planeEquationNormalPoint,
&Vector4Test::swizzleType,
&Vector4Test::debug,
&Vector4Test::configuration});
@ -259,6 +265,34 @@ void Vector4Test::twoComponent() {
CORRADE_COMPARE(d, 1.0f);
}
void Vector4Test::planeEquationThreePoints() {
const Vector3 a{1.0f, 0.5f, 3.0f};
const Vector3 b{1.5f, 1.5f, 2.5f};
const Vector3 c{2.0f, 1.5f, 1.0f};
const Vector4 eq = Math::planeEquation(a, b, c);
CORRADE_COMPARE(Math::dot(a, eq.xyz()) + eq.w(), 0.0f);
CORRADE_COMPARE(Math::dot(b, eq.xyz()) + eq.w(), 0.0f);
CORRADE_COMPARE(Math::dot(c, eq.xyz()) + eq.w(), 0.0f);
CORRADE_COMPARE(eq, (Vector4{-0.9045340f, 0.3015113f, -0.3015113f, 1.658312f}));
/* Different winding order should only give a negated normal */
CORRADE_COMPARE(Math::planeEquation(a, c, b), -eq);
}
void Vector4Test::planeEquationNormalPoint() {
const Vector3 a{1.0f, 0.5f, 3.0f};
const Vector3 normal{-0.9045340f, 0.3015113f, -0.3015113f};
const Vector4 eq = Math::planeEquation(normal, a);
const Vector3 b{1.5f, 1.5f, 2.5f};
const Vector3 c{2.0f, 1.5f, 1.0f};
CORRADE_COMPARE(Math::dot(a, eq.xyz()) + eq.w(), 0.0f);
CORRADE_COMPARE(Math::dot(b, eq.xyz()) + eq.w(), 0.0f);
CORRADE_COMPARE(Math::dot(c, eq.xyz()) + eq.w(), 0.0f);
CORRADE_COMPARE(eq, (Vector4{-0.9045340f, 0.3015113f, -0.3015113f, 1.658312f}));
}
void Vector4Test::swizzleType() {
constexpr Vector4i orig;
constexpr auto c = swizzle<'y', 'a', 'y', 'x'>(orig);

2
src/Magnum/Math/Vector3.h

@ -48,7 +48,7 @@ Which is equivalent to the common one (source:
https://twitter.com/sjb3d/status/563640846671953920): @f[
\boldsymbol a \times \boldsymbol b = \begin{pmatrix}a_yb_z - a_zb_y \\ a_zb_x - a_xb_z \\ a_xb_y - a_yb_x \end{pmatrix}
@f]
@see @ref cross(const Vector2<T>&, const Vector2<T>&)
@see @ref cross(const Vector2<T>&, const Vector2<T>&), @ref planeEquation()
*/
template<class T> inline Vector3<T> cross(const Vector3<T>& a, const Vector3<T>& b) {
return swizzle<'y', 'z', 'x'>(a*swizzle<'y', 'z', 'x'>(b) -

50
src/Magnum/Math/Vector4.h

@ -26,7 +26,7 @@
*/
/** @file
* @brief Class @ref Magnum::Math::Vector4
* @brief Class @ref Magnum::Math::Vector4, function @ref Magnum::Math::planeEquation()
*/
#include "Magnum/Math/Vector3.h"
@ -200,6 +200,54 @@ template<class T> class Vector4: public Vector<4, T> {
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(4, Vector4)
};
/** @relatesalso Vector4
@brief Create a plane equation from three points
Assuming the three points form a triangle in a counter-clockwise winding,
creates a plane equation in the following form: @f[
ax + by + cz + d = 0
@f]
The first three coefficients describe the *scaled* normal
@f$ \boldsymbol{n} = (a, b, c)^T @f$ and are calculated using a cross product.
The coefficient @f$ d @f$ is calculated using a dot product with the normal
@f$ \boldsymbol{n} @f$ using the first point in order to satisfy the equation
when assigning @f$ \boldsymbol{p_i} @f$ to @f$ x @f$, @f$ y @f$, @f$ z @f$. @f[
\begin{array}{rcl}
\boldsymbol{n} & = & (\boldsymbol{p_1} - \boldsymbol{p_0}) \times (\boldsymbol{p_2} - \boldsymbol{p_0}) \\
d & = & - \boldsymbol{n} \cdot \boldsymbol{p_0}
\end{array}
@f]
@see @ref planeEquation(const Vector3<T>&, const Vector3<T>&), @ref cross(),
@ref dot()
*/
template<class T> Vector4<T> planeEquation(const Vector3<T>& p0, const Vector3<T>& p1, const Vector3<T>& p2) {
const Vector3<T> normal = Math::cross(p1 - p0, p2 - p0).normalized();
return {normal, -Math::dot(normal, p0)};
}
/** @relatesalso Vector4
@brief Create a plane equation from a normal and a point
Creates a plane equation in the following form: @f[
ax + by + cz + d = 0
@f]
The first three coefficients describe the *scaled* normal
@f$ \boldsymbol{n} = (a, b, c)^T @f$, the coefficient @f$ d @f$ is calculated
using a dot product with the normal @f$ \boldsymbol{n} @f$ using the point
@f$ \boldsymbol{p} @f$ in order to satisfy the equation when assigning
@f$ \boldsymbol{p} @f$ to @f$ x @f$, @f$ y @f$, @f$ z @f$. @f[
d = - \boldsymbol{n} \cdot \boldsymbol{p}
@f]
@see @ref planeEquation(const Vector3<T>&, const Vector3<T>&, const Vector3<T>&),
@ref dot()
*/
template<class T> Vector4<T> planeEquation(const Vector3<T>& normal, const Vector3<T>& point) {
return {normal, -Math::dot(normal, point)};
}
#ifndef DOXYGEN_GENERATING_OUTPUT
MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(4, Vector4)
#endif

Loading…
Cancel
Save