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 @ref Math::Constants::piQuarter()
- Added a convenience function @ref Math::select() as a constant - Added a convenience function @ref Math::select() as a constant
interpolation counterpart to @ref Math::lerp() 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 - Ability to convert @ref Math::BoolVector from and to external
representation 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 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 of interest, for example when testing on which half space of the plane the
point lies. point lies.
@see @ref pointPlaneNormalized() @see @ref planeEquation(), @ref pointPlaneNormalized()
*/ */
template<class T> inline T pointPlaneScaled(const Vector3<T>& point, const Vector4<T>& plane) { template<class T> inline T pointPlaneScaled(const Vector3<T>& point, const Vector4<T>& plane) {
return dot(plane.xyz(), point) + plane.w(); 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() 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, is more efficient. If merely the sign of the distance is of interest,
@ref pointPlaneScaled() is more efficient. @ref pointPlaneScaled() is more efficient.
@see @ref planeEquation()
*/ */
template<class T> inline T pointPlane(const Vector3<T>& point, const Vector4<T>& plane) { template<class T> inline T pointPlane(const Vector3<T>& point, const Vector4<T>& plane) {
return pointPlaneScaled<T>(point, plane)/plane.xyz().length(); 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 More efficient than @ref pointPlane() in cases where the plane's normal is
normalized. Equivalent to @ref pointPlaneScaled() but with assertion added on normalized. Equivalent to @ref pointPlaneScaled() but with assertion added on
top. top.
@see @ref planeEquation()
*/ */
template<class T> inline T pointPlaneNormalized(const Vector3<T>& point, const Vector4<T>& plane) { template<class T> inline T pointPlaneNormalized(const Vector3<T>& point, const Vector4<T>& plane) {
CORRADE_ASSERT(plane.xyz().isNormalized(), CORRADE_ASSERT(plane.xyz().isNormalized(),

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

@ -68,6 +68,9 @@ struct Vector4Test: Corrade::TestSuite::Tester {
void threeComponent(); void threeComponent();
void twoComponent(); void twoComponent();
void planeEquationThreePoints();
void planeEquationNormalPoint();
void swizzleType(); void swizzleType();
void debug(); void debug();
void configuration(); void configuration();
@ -93,6 +96,9 @@ Vector4Test::Vector4Test() {
&Vector4Test::threeComponent, &Vector4Test::threeComponent,
&Vector4Test::twoComponent, &Vector4Test::twoComponent,
&Vector4Test::planeEquationThreePoints,
&Vector4Test::planeEquationNormalPoint,
&Vector4Test::swizzleType, &Vector4Test::swizzleType,
&Vector4Test::debug, &Vector4Test::debug,
&Vector4Test::configuration}); &Vector4Test::configuration});
@ -259,6 +265,34 @@ void Vector4Test::twoComponent() {
CORRADE_COMPARE(d, 1.0f); 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() { void Vector4Test::swizzleType() {
constexpr Vector4i orig; constexpr Vector4i orig;
constexpr auto c = swizzle<'y', 'a', 'y', 'x'>(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[ 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} \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] @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) { 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) - return swizzle<'y', 'z', 'x'>(a*swizzle<'y', 'z', 'x'>(b) -

50
src/Magnum/Math/Vector4.h

@ -26,7 +26,7 @@
*/ */
/** @file /** @file
* @brief Class @ref Magnum::Math::Vector4 * @brief Class @ref Magnum::Math::Vector4, function @ref Magnum::Math::planeEquation()
*/ */
#include "Magnum/Math/Vector3.h" #include "Magnum/Math/Vector3.h"
@ -200,6 +200,54 @@ template<class T> class Vector4: public Vector<4, T> {
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(4, Vector4) 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 #ifndef DOXYGEN_GENERATING_OUTPUT
MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(4, Vector4) MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(4, Vector4)
#endif #endif

Loading…
Cancel
Save