Program Listing for File triangle.cc

Return to documentation for file (src/triangle.cc)

/*
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *                                                                     *
 * The ACME project                                                    *
 *                                                                     *
 * Copyright (c) 2020, Davide Stocco and Enrico Bertolazzi.            *
 *                                                                     *
 * The ACME project and its components are supplied under the terms of *
 * the open source BSD 2-Clause License. The contents of the ACME      *
 * project and its components may not be copied or disclosed except in *
 * accordance with the terms of the BSD 2-Clause License.              *
 *                                                                     *
 * URL: https://opensource.org/licenses/BSD-2-Clause                   *
 *                                                                     *
 *    Davide Stocco                                                    *
 *    Department of Industrial Engineering                             *
 *    University of Trento                                             *
 *    e-mail: davide.stocco@unitn.it                                   *
 *                                                                     *
 *    Enrico Bertolazzi                                                *
 *    Department of Industrial Engineering                             *
 *    University of Trento                                             *
 *    e-mail: enrico.bertolazzi@unitn.it                               *
 *                                                                     *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/


#ifndef DOXYGEN_SHOULD_SKIP_THIS

#include "acme.hh"

namespace acme
{

  /*\
   |   _        _                   _
   |  | |_ _ __(_) __ _ _ __   __ _| | ___
   |  | __| '__| |/ _` | '_ \ / _` | |/ _ \
   |  | |_| |  | | (_| | | | | (_| | |  __/
   |   \__|_|  |_|\__,_|_| |_|\__, |_|\___|
   |                          |___/
  \*/

  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  triangle::triangle(void)
  {
  }

  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  triangle::triangle(
    real vertex0_x,
    real vertex0_y,
    real vertex0_z,
    real vertex1_x,
    real vertex1_y,
    real vertex1_z,
    real vertex2_x,
    real vertex2_y,
    real vertex2_z
  )
    : m_vertex{point(vertex0_x, vertex0_y, vertex0_z),
               point(vertex1_x, vertex1_y, vertex1_z),
               point(vertex2_x, vertex2_y, vertex2_z)}
  {
  }

  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  triangle::triangle(
    point const & vertex0,
    point const & vertex1,
    point const & vertex2
  )
    : m_vertex{vertex0, vertex1, vertex2}
  {
  }

  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  triangle::triangle(
    point const vertex[3]
  )
    : m_vertex{vertex[0], vertex[1], vertex[2]}
  {
  }

  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  bool
  triangle::isApprox(
    triangle const & triangle_in,
    real             tolerance
  )
    const
  {
    return this->m_vertex[0].isApprox(triangle_in.m_vertex[0], tolerance) &&
           this->m_vertex[1].isApprox(triangle_in.m_vertex[1], tolerance) &&
           this->m_vertex[2].isApprox(triangle_in.m_vertex[2], tolerance);
  }

  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  point const &
  triangle::vertex(
    integer i
  )
    const
  {
    #define CMD "acme::triangle::vertex(): "

    ACME_ASSERT(i < 3,
      CMD "index out of bounds [0,2].")
    return this->m_vertex[i];

    #undef CMD
  }

  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  point &
  triangle::vertex(
    integer i
  )
  {
    #define CMD "acme::triangle::vertex(): "

    ACME_ASSERT(i < 3,
      CMD "index out of bounds [0,2].")
    return this->m_vertex[i];

    #undef CMD
  }

  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  point const &
  triangle::operator[](
    integer i
  )
    const
  {
    #define CMD "acme::triangle::operator[]: "

    ACME_ASSERT(i < 3,
      CMD "index out of bounds [0,2].")
    return this->m_vertex[i];

    #undef CMD
  }

  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  point &
  triangle::operator[](
    integer i
  )
  {
    #define CMD "acme::triangle::operator[]: "

    ACME_ASSERT(i < 3,
      CMD "index out of bounds [0,2].")
    return this->m_vertex[i];

    #undef CMD
  }

  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  point
  triangle::centroid(void)
    const
  {
    return (this->m_vertex[0] + this->m_vertex[1] + this->m_vertex[2]) / real(3.0);
  }

  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  segment
  triangle::edge(
    integer i
  )
    const
  {
    #define CMD "acme::triangle::edge(): "

    ACME_ASSERT(i < 3,
      CMD "index out of bounds [0,2].")
    if (i == 0)
      {return segment(this->m_vertex[0], this->m_vertex[1]);}
    else if (i == 1)
      {return segment(this->m_vertex[1], this->m_vertex[2]);}
    else // (i == 2)
      {return segment(this->m_vertex[2], this->m_vertex[0]);}

    #undef CMD
  }

  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  vec3
  triangle::normal(void)
    const
  {
    return (this->m_vertex[1] - this->m_vertex[0]).cross(this->m_vertex[2] - this->m_vertex[0]).normalized();
  }

  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  void
  triangle::swap(
    integer i,
    integer j
  )
  {
    point tmp_vertex_i(this->m_vertex[i]);
    point tmp_vertex_j(this->m_vertex[j]);
    this->m_vertex[i] = tmp_vertex_j;
    this->m_vertex[j] = tmp_vertex_i;
  }

  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  real
  triangle::perimeter(void)
    const
  {
    return (this->m_vertex[0] - this->m_vertex[1]).norm() +
           (this->m_vertex[1] - this->m_vertex[2]).norm() +
           (this->m_vertex[2] - this->m_vertex[0]).norm();
  }

  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  real
  triangle::area(void)
    const
  {
    return ((this->m_vertex[1] - this->m_vertex[0]).cross(this->m_vertex[2] - this->m_vertex[0])).norm() / real(2.0);
  }

  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  void
  triangle::barycentric(
    point const & point_in,
    real        & u,
    real        & v,
    real        & w
  )
    const
  {
    point v0(this->m_vertex[1] - this->m_vertex[0]);
    point v1(this->m_vertex[2] - this->m_vertex[0]);
    point v2(point_in - this->m_vertex[0]);
    real  d00   = v0.dot(v0);
    real  d01   = v0.dot(v1);
    real  d11   = v1.dot(v1);
    real  d20   = v2.dot(v0);
    real  d21   = v2.dot(v1);
    real  denom = d00 * d11 - d01 * d01;
    v = (d11 * d20 - d01 * d21) / denom;
    w = (d00 * d21 - d01 * d20) / denom;
    u = real(1.0) - v - w;
  }

  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  plane
  triangle::layingPlane(void)
    const
  {
    return plane(this->centroid(), this->normal());
  }

  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  void
  triangle::translate(
    vec3 const & vector_in
  )
  {
    this->m_vertex[0] = vector_in + this->m_vertex[0];
    this->m_vertex[1] = vector_in + this->m_vertex[1];
    this->m_vertex[2] = vector_in + this->m_vertex[2];
  }

  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  void
  triangle::transform(
    affine const & affine_in
  )
  {
    this->m_vertex[0].transform(affine_in);
    this->m_vertex[1].transform(affine_in);
    this->m_vertex[2].transform(affine_in);
  }

  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  bool
  triangle::isInside(
    point const & point_in,
    real          tolerance
  )
    const
  {
    real u, v, w;
    this->barycentric(point_in, u, v, w);
    if (u >= real(0.0) - tolerance && u <= real(1.0) + tolerance &&
        v >= real(0.0) - tolerance && v <= real(1.0) + tolerance &&
        w >= real(0.0) - tolerance && w <= real(1.0) + tolerance)
    {
      return this->layingPlane().isInside(point_in, tolerance);
    }
    else
    {
      return false;
    }
  }

  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  bool
  triangle::isDegenerated(
    real tolerance
  )
    const
  {
    return IsApprox((this->m_vertex[0] - this->m_vertex[1]).norm(), real(0.0), tolerance) ||
           IsApprox((this->m_vertex[1] - this->m_vertex[2]).norm(), real(0.0), tolerance) ||
           IsApprox((this->m_vertex[2] - this->m_vertex[0]).norm(), real(0.0), tolerance);
  }

  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  bool
  triangle::clamp(
    vec3 & min,
    vec3 & max
  )
    const
  {
    min(0) = std::min(this->m_vertex[0].x(), std::min(this->m_vertex[1].x(), this->m_vertex[2].x()));
    min(1) = std::min(this->m_vertex[0].y(), std::min(this->m_vertex[1].y(), this->m_vertex[2].y()));
    min(2) = std::min(this->m_vertex[0].z(), std::min(this->m_vertex[1].z(), this->m_vertex[2].z()));
    max(0) = std::max(this->m_vertex[0].x(), std::max(this->m_vertex[1].x(), this->m_vertex[2].x()));
    max(1) = std::max(this->m_vertex[0].y(), std::max(this->m_vertex[1].y(), this->m_vertex[2].y()));
    max(2) = std::max(this->m_vertex[0].z(), std::max(this->m_vertex[1].z(), this->m_vertex[2].z()));
    return this->isClampable();
  }

  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  bool
  triangle::clamp(
    real & min_x,
    real & min_y,
    real & min_z,
    real & max_x,
    real & max_y,
    real & max_z
  )
    const
  {
    min_x = std::min(this->m_vertex[0].x(), std::min(this->m_vertex[1].x(), this->m_vertex[2].x()));
    min_y = std::min(this->m_vertex[0].y(), std::min(this->m_vertex[1].y(), this->m_vertex[2].y()));
    min_z = std::min(this->m_vertex[0].z(), std::min(this->m_vertex[1].z(), this->m_vertex[2].z()));
    max_x = std::max(this->m_vertex[0].x(), std::max(this->m_vertex[1].x(), this->m_vertex[2].x()));
    max_y = std::max(this->m_vertex[0].y(), std::max(this->m_vertex[1].y(), this->m_vertex[2].y()));
    max_z = std::max(this->m_vertex[0].z(), std::max(this->m_vertex[1].z(), this->m_vertex[2].z()));
    return this->isClampable();
  }

  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

} // namespace acme

#endif