| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef LIB_ESCHER_GEOMETRY_PLANE_OPS_H_ |
| #define LIB_ESCHER_GEOMETRY_PLANE_OPS_H_ |
| |
| #include "lib/escher/geometry/type_utils.h" |
| #include "lib/escher/geometry/types.h" |
| |
| namespace escher { |
| |
| // Transform the world-space plane into object space. NOTE: use the same matrix |
| // that you would to transform an object into world space. This may seem |
| // counter-intuitive; here is the reasoning: |
| // |
| // In order to transform a plane in world-space, you multiply it by the |
| // transpose of the inverse of the transform matrix. For example, see: |
| // https://stackoverflow.com/questions/7685495/transforming-a-3d-plane-using-a-4x4-matrix |
| // However, we don't want to move a plane in world space, we want to move it to |
| // object space. To do this, we need the inverse of |model_to_world_matrix|. |
| // However, once we have that matrix, the first thing we would naively do is |
| // invert it again, then transpose it. The two inversions cancel each other |
| // out, and we can also avoid the transpose (see comment below). |
| template <typename PlaneT> |
| PlaneT TransformPlane(const mat4& model_to_world_matrix, const PlaneT& plane) { |
| // Instead of transposing the matrix, simply do the multiplication with the |
| // vector on the left-hand side. |
| vec4 v = Homo4(plane.dir(), -plane.dist()) * model_to_world_matrix; |
| |
| // Must renormalize in case of scaling. |
| float normalization_factor = 1 / glm::length(vec3(v)); |
| v *= normalization_factor; |
| |
| // Shorten the homogeneous direction vector before passing it to plane |
| // constructor. In the case of plane2, use the specialized vec3 constructor |
| // to further shorten the direction to vec2, and also ensure that the |
| // z-coordinate is zero. |
| return PlaneT(vec3(v), -v.w); |
| } |
| |
| // Transform the world-space plane into object space. This is an optimization |
| // of TransformPlane(): it computes the same result without needing a matrix |
| // multiplication. |
| template <typename PlaneT> |
| PlaneT TranslatePlane(const typename PlaneT::VectorType& model_to_world_vec, |
| const PlaneT& plane) { |
| return PlaneT(plane.dir(), |
| glm::dot(-model_to_world_vec, plane.dir()) + plane.dist()); |
| } |
| |
| // Transform the world-space plane into object space. This is an optimization |
| // of TransformPlane(): it computes the same result without needing a matrix |
| // multiplication. |
| template <typename PlaneT> |
| PlaneT ScalePlane(float model_to_world_scale, const PlaneT& plane) { |
| FXL_DCHECK(model_to_world_scale > kEpsilon); |
| return PlaneT(plane.dir(), plane.dist() / model_to_world_scale); |
| } |
| |
| // Return the distance from the point to the plane. This distance is oriented: |
| // it can be positive or negative (or zero, if the point is on the plane). A |
| // positive value means that the point is inside the half-space defined by the |
| // plane, and a negative value means that the point is outside. |
| template <typename VecT> |
| float PlaneDistanceToPoint(const planeN<VecT>& plane, const VecT& point) { |
| return glm::dot(plane.dir(), point) - plane.dist(); |
| } |
| |
| // Promote |point| to 3D in order to be tested against 3D plane. |
| inline float PlaneDistanceToPoint(const planeN<vec3>& plane, |
| const vec2& point) { |
| return PlaneDistanceToPoint(plane, vec3(point, 0)); |
| } |
| |
| // Demote |point| to 2D in order to be tested against 2D plane. |
| inline float PlaneDistanceToPoint(const planeN<vec2>& plane, |
| const vec3& point) { |
| return PlaneDistanceToPoint(plane, vec2(point)); |
| } |
| |
| // Return true if point is contained within the half-space of the oriented |
| // plane, or on the boundary. |
| template <typename PlaneT, typename VecT> |
| bool PlaneClipsPoint(const PlaneT& plane, const VecT& point) { |
| return PlaneDistanceToPoint(plane, point) < 0.f; |
| } |
| |
| } // namespace escher |
| |
| #endif // LIB_ESCHER_GEOMETRY_PLANE_OPS_H_ |