Commit 94cbffc9 authored by Jan Möbius's avatar Jan Möbius

Merge branch 'c++11_matrix' into 'master'

C++11 matrix

Added a modern (C++11) 3x3 matrix class and a closest point in triangle query that builds on top of it.

See merge request !148
parents d03842e6 ae668cf2
Pipeline #3358 passed with stage
in 57 minutes and 37 seconds
......@@ -61,6 +61,8 @@
#include <vector>
#include <iostream>
#include "../Math/Matrix3x3T.hh"
namespace ACG {
namespace Geometry {
......@@ -631,7 +633,72 @@ roundness( const VectorT<Scalar, N>& _v0,
const VectorT<Scalar, N>& _v1,
const VectorT<Scalar, N>& _v2 );
/** @} */
/** @} */
template<typename Vector>
Vector closestPointLineSegment(Vector x, Vector p1, Vector p2) {
const auto delta = ((p2-p1)|(x-p1)) / (p2-p1).sqrnorm();
//std::cout << "\x1b[32mdelta = " << delta << "\x1b[0m" << std::endl;
if (delta <= 0) {
//std::cout << "\x1b[43mdelta <= 0\x1b[0m" << std::endl;
return p1;
} else if (delta >= 1) {
//std::cout << "\x1b[43mdelta >= 1\x1b[0m" << std::endl;
return p2;
} else if (delta != delta) { // p1 = p2 or x = p1
//std::cout << "\x1b[43mdelta != delta\x1b[0m" << std::endl;
return (x-p1).sqrnorm() < (x-p2).sqrnorm() ? p1 : p2;
} else {
//std::cout << "\x1b[43mdelta \\in [0, 1]\x1b[0m" << std::endl;
return (1 - delta) * p1 + delta * p2;
}
};
template<typename Vector>
Vector closestPointTri(Vector p, Vector a, Vector b, Vector c) {
constexpr double thresh = 1e-8;
const auto n = ((b - a) % (c - a)); // normalization unnecessary
if ((b-a).sqrnorm() < thresh || (c-a).sqrnorm() < thresh || n.sqrnorm() < thresh) {
//std::cout << "\x1b[42mDegenerate case.\x1b[0m" << std::endl;
// Degenerate triangle. Find distance to longest segment.
std::array<ACG::Vec3d, 2> max_segment = {a, b};
double max_len = (b-a).sqrnorm();
if ((c-a).sqrnorm() > max_len)
max_segment = {a, c};
if ((c-b).sqrnorm() > max_len)
max_segment = {b, c};
// closestPointLineSegment is stable, even if the segment is super short
return closestPointLineSegment(p, max_segment[0], max_segment[1]);
}
const auto abd = Matrix3x3d::fromColumns(a-c, b-c, n).inverse() * (p - c);
const bool alpha = (abd[0] >= 0.0),
beta = (abd[1] >= 0.0),
gamma = (1.0-abd[0]-abd[1] >= 0.0);
if (alpha && beta && gamma) {
//std::cout << "\x1b[42mInside case.\x1b[0m" << std::endl;
// Inside triangle.
return abd[0] * a + abd[1] * b + (1.0 - abd[0] - abd[1]) * c;
} else if (!alpha) {
//std::cout << "\x1b[42m!alpha case.\x1b[0m" << std::endl;
// Closest to line segment (b, c).
return closestPointLineSegment(p, b, c);
} else if (!beta) {
//std::cout << "\x1b[42m!beta case.\x1b[0m" << std::endl;
// Closest to line segment (a, c).
return closestPointLineSegment(p, a, c);
} else if (!gamma) {
//std::cout << "\x1b[42m!gamma case.\x1b[0m" << std::endl;
// Closest to line segment (a, b).
return closestPointLineSegment(p, a, b);
} else {
throw std::logic_error("This cannot happen.");
}
}
//=============================================================================
} // namespace Geometry
......
#ifndef ACG_MATH_MATRIX3X3T_HH_
#define ACG_MATH_MATRIX3X3T_HH_
#include <array>
#include <ostream>
#include <ACG/Math/VectorT.hh>
#include <algorithm>
#include <cmath>
#if defined(_MSC_VER) && _MSC_VER < 1900
#define constexpr
typedef unsigned char uint_fast8_t;
#endif
namespace ACG {
/**
* Small, kinda fast 3x3 matrix class.
*/
template<typename Scalar>
class Matrix3x3T {
public:
typedef typename OpenMesh::VectorT<Scalar, 3> Vec3;
static Matrix3x3T<Scalar> fromColumns(Vec3 c1, Vec3 c2, Vec3 c3) {
return Matrix3x3T<Scalar> {{
c1[0], c2[0], c3[0],
c1[1], c2[1], c3[1],
c1[2], c2[2], c3[2],
}};
}
static Matrix3x3T<Scalar> fromRows(Vec3 r1, Vec3 r2, Vec3 r3) {
return Matrix3x3T<Scalar> {{
r1[0], r1[1], r1[2],
r2[0], r2[1], r2[2],
r3[0], r3[1], r3[2]
}};
}
static constexpr Matrix3x3T<Scalar> identity() {
return {{
1, 0, 0,
0, 1, 0,
0, 0, 1
}};
}
static constexpr Matrix3x3T<Scalar> zero() {
return {{
0, 0, 0,
0, 0, 0,
0, 0, 0
}};
}
public:
Matrix3x3T() = default;
/**
* Initialize matrix from array in row major format.
*/
constexpr Matrix3x3T(std::array<Scalar, 9> row_major) :
values_(std::move(row_major)) {}
constexpr bool operator==(const Matrix3x3T &rhs) const {
return values_ == rhs.values_;
}
//Matrix3x3T(std::initializer_list<Scalar> row_major) {
// static_assert(row_major.size() == 9, "Need exactly 9 values.");
// std::copy(row_major.begin(), row_major.end(), this->begin());
//}
/// Map row/column index to linearized index.
constexpr static uint_fast8_t indexof(uint_fast8_t r, uint_fast8_t c) {
return r*3+c;
}
constexpr const Scalar &operator() (uint_fast8_t r, uint_fast8_t c) const {
return values_[indexof(r, c)];
}
Scalar &operator() (uint_fast8_t r, uint_fast8_t c) {
return values_[indexof(r, c)];
}
/// Linearized row major access.
constexpr const Scalar &operator[] (uint_fast8_t i) const {
return values_[i];
}
/// Linearized row major access.
Scalar &operator[] (uint_fast8_t i) {
return values_[i];
}
constexpr Matrix3x3T operator*(const Matrix3x3T &rhs) const {
return Matrix3x3T {{
(*this)(0, 0) * rhs(0, 0) + (*this)(0, 1) * rhs(1, 0) + (*this)(0, 2) * rhs(2, 0),
(*this)(0, 0) * rhs(0, 1) + (*this)(0, 1) * rhs(1, 1) + (*this)(0, 2) * rhs(2, 1),
(*this)(0, 0) * rhs(0, 2) + (*this)(0, 1) * rhs(1, 2) + (*this)(0, 2) * rhs(2, 2),
(*this)(1, 0) * rhs(0, 0) + (*this)(1, 1) * rhs(1, 0) + (*this)(1, 2) * rhs(2, 0),
(*this)(1, 0) * rhs(0, 1) + (*this)(1, 1) * rhs(1, 1) + (*this)(1, 2) * rhs(2, 1),
(*this)(1, 0) * rhs(0, 2) + (*this)(1, 1) * rhs(1, 2) + (*this)(1, 2) * rhs(2, 2),
(*this)(2, 0) * rhs(0, 0) + (*this)(2, 1) * rhs(1, 0) + (*this)(2, 2) * rhs(2, 0),
(*this)(2, 0) * rhs(0, 1) + (*this)(2, 1) * rhs(1, 1) + (*this)(2, 2) * rhs(2, 1),
(*this)(2, 0) * rhs(0, 2) + (*this)(2, 1) * rhs(1, 2) + (*this)(2, 2) * rhs(2, 2),
}};
}
constexpr Vec3 operator*(const Vec3 &rhs) const {
return Vec3(
(*this)(0, 0) * rhs[0] + (*this)(0, 1) * rhs[1] + (*this)(0, 2) * rhs[2],
(*this)(1, 0) * rhs[0] + (*this)(1, 1) * rhs[1] + (*this)(1, 2) * rhs[2],
(*this)(2, 0) * rhs[0] + (*this)(2, 1) * rhs[1] + (*this)(2, 2) * rhs[2]
);
}
constexpr friend Vec3 operator*(Vec3 v, const Matrix3x3T &rhs) {
return Vec3(
rhs(0, 0) * v[0] + rhs(0, 1) * v[1] + rhs(0, 2) * v[2],
rhs(1, 0) * v[0] + rhs(1, 1) * v[1] + rhs(1, 2) * v[2],
rhs(2, 0) * v[0] + rhs(2, 1) * v[1] + rhs(2, 2) * v[2]
);
}
constexpr Matrix3x3T operator*(Scalar c) const {
return Matrix3x3T {{
(*this)[0] * c, (*this)[1] * c, (*this)[2] * c,
(*this)[3] * c, (*this)[4] * c, (*this)[5] * c,
(*this)[6] * c, (*this)[7] * c, (*this)[8] * c,
}};
}
constexpr friend Matrix3x3T operator*(Scalar c, const Matrix3x3T &rhs) {
return Matrix3x3T {{
rhs[0] * c, rhs[1] * c, rhs[2] * c,
rhs[3] * c, rhs[4] * c, rhs[5] * c,
rhs[6] * c, rhs[7] * c, rhs[8] * c,
}};
}
constexpr Matrix3x3T operator+ (const Matrix3x3T &rhs) const {
return Matrix3x3T {{
(*this)[0] + rhs[0], (*this)[1] + rhs[1], (*this)[2] + rhs[2],
(*this)[3] + rhs[3], (*this)[4] + rhs[4], (*this)[5] + rhs[5],
(*this)[6] + rhs[6], (*this)[7] + rhs[7], (*this)[8] + rhs[8],
}};
}
constexpr Matrix3x3T operator- (const Matrix3x3T &rhs) const {
return Matrix3x3T {{
(*this)[0] - rhs[0], (*this)[1] - rhs[1], (*this)[2] - rhs[2],
(*this)[3] - rhs[3], (*this)[4] - rhs[4], (*this)[5] - rhs[5],
(*this)[6] - rhs[6], (*this)[7] - rhs[7], (*this)[8] - rhs[8],
}};
}
constexpr Matrix3x3T operator- () const {
return Matrix3x3T {{
-values_[0], -values_[1], -values_[2],
-values_[3], -values_[4], -values_[5],
-values_[6], -values_[7], -values_[8]
}};
}
const Matrix3x3T &operator*=(const Matrix3x3T &rhs) {
(*this) = operator*(rhs);
return *this;
}
constexpr Scalar det() const {
return (*this)(0, 0) * ((*this)(1, 1) * (*this)(2, 2) - (*this)(2, 1) * (*this)(1, 2)) -
(*this)(0, 1) * ((*this)(1, 0) * (*this)(2, 2) - (*this)(1, 2) * (*this)(2, 0)) +
(*this)(0, 2) * ((*this)(1, 0) * (*this)(2, 1) - (*this)(1, 1) * (*this)(2, 0));
/*
return (*this)(0, 0) * (*this)(1, 1) * (*this)(2, 2) +
(*this)(1, 0) * (*this)(2, 1) * (*this)(0, 2) +
(*this)(2, 0) * (*this)(0, 1) * (*this)(1, 2) -
(*this)(0, 0) * (*this)(2, 1) * (*this)(1, 2) -
(*this)(2, 0) * (*this)(1, 1) * (*this)(0, 2) -
(*this)(1, 0) * (*this)(0, 1) * (*this)(2, 2)
*/
}
constexpr Scalar trace() const {
return (*this)[0] + (*this)[4] + (*this)[8];
}
void transpose() {
std::swap(values_[1], values_[3]);
std::swap(values_[2], values_[6]);
std::swap(values_[5], values_[7]);
}
constexpr Matrix3x3T transposed() const {
return Matrix3x3T {{
values_[0], values_[3], values_[6],
values_[1], values_[4], values_[7],
values_[2], values_[5], values_[8],
}};
}
void invert() {
*this = inverse();
}
Matrix3x3T inverse() const {
const Scalar invdet = 1.0 / det();
return Matrix3x3T {{
((*this)(1, 1) * (*this)(2, 2) - (*this)(2, 1) * (*this)(1, 2)) * invdet,
((*this)(0, 2) * (*this)(2, 1) - (*this)(0, 1) * (*this)(2, 2)) * invdet,
((*this)(0, 1) * (*this)(1, 2) - (*this)(0, 2) * (*this)(1, 1)) * invdet,
((*this)(1, 2) * (*this)(2, 0) - (*this)(1, 0) * (*this)(2, 2)) * invdet,
((*this)(0, 0) * (*this)(2, 2) - (*this)(0, 2) * (*this)(2, 0)) * invdet,
((*this)(1, 0) * (*this)(0, 2) - (*this)(0, 0) * (*this)(1, 2)) * invdet,
((*this)(1, 0) * (*this)(2, 1) - (*this)(2, 0) * (*this)(1, 1)) * invdet,
((*this)(2, 0) * (*this)(0, 1) - (*this)(0, 0) * (*this)(2, 1)) * invdet,
((*this)(0, 0) * (*this)(1, 1) - (*this)(1, 0) * (*this)(0, 1)) * invdet,
}};
}
constexpr Scalar frobeniusSquared() const {
return std::inner_product(
values_.begin(), values_.end(), values_.begin(), Scalar(0.0));
}
constexpr double frobenius() const {
return std::sqrt(frobeniusSquared());
}
friend
std::ostream &operator<< (std::ostream &os, const Matrix3x3T &m) {
os << "[[" << m[0] << ", " << m[1] << ", " << m[2] << "], "
"[" << m[3] << ", " << m[4] << ", " << m[5] << "], "
"[" << m[6] << ", " << m[7] << ", " << m[8] << "]]";
return os;
}
private:
std::array<Scalar, 9> values_;
};
typedef Matrix3x3T<float> Matrix3x3f;
typedef Matrix3x3T<double> Matrix3x3d;
} /* namespace ACG */
#if defined(_MSC_VER) && _MSC_VER < 1900
#undef constexpr
#endif
#endif /* ACG_MATH_MATRIX3X3T_HH_ */
/*===========================================================================*\
* *
* OpenFlipper *
* Copyright (c) 2001-2015, RWTH-Aachen University *
* Department of Computer Graphics and Multimedia *
* All rights reserved. *
* www.openflipper.org *
* *
*---------------------------------------------------------------------------*
* This file is part of OpenFlipper. *
*---------------------------------------------------------------------------*
* *
* Redistribution and use in source and binary forms, with or without *
* modification, are permitted provided that the following conditions *
* are met: *
* *
* 1. Redistributions of source code must retain the above copyright notice, *
* this list of conditions and the following disclaimer. *
* *
* 2. Redistributions in binary form must reproduce the above copyright *
* notice, this list of conditions and the following disclaimer in the *
* documentation and/or other materials provided with the distribution. *
* *
* 3. Neither the name of the copyright holder nor the names of its *
* contributors may be used to endorse or promote products derived from *
* this software without specific prior written permission. *
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
* *
\*===========================================================================*/
#include <gtest/gtest.h>
#include <ACG/Math/VectorT.hh>
#include <ACG/Geometry/Algorithms.hh>
#include "../Math/MatrixTestHelper.hh"
namespace {
TEST(Algorithms_ClosestPoints, closestPointTri_inside) {
// Closest point inside
{
ACG::Vec3d closest_point = ACG::Geometry::closestPointTri(
ACG::Vec3d(0.180189728737, 0.284434795380, 0.685222446918),
ACG::Vec3d(0.780881822109, -0.711405277252, 0.000000000000),
ACG::Vec3d(-1.080165147781, 0.470909714699, 0.000000000000),
ACG::Vec3d(0.663306236267, 1.208429455757, 0.000000000000)
);
EXPECT_TRUE(areClose(closest_point, ACG::Vec3d(0.180189728737, 0.284434795380, 0.000000000000)));
}
{
ACG::Vec3d closest_point = ACG::Geometry::closestPointTri(
ACG::Vec3d(0.180189728737, 0.284434795380, 0.685222446918),
ACG::Vec3d(0.898327171803, -0.711405336857, 0.402669787407),
ACG::Vec3d(-1.138887882233, 0.470909774303, -0.511726200581),
ACG::Vec3d(0.738806843758, 1.208429455757, -0.109056398273)
);
EXPECT_TRUE(areClose(closest_point, ACG::Vec3d(0.379620872542, 0.129005603666, 0.039932640059)));
}
{
ACG::Vec3d closest_point = ACG::Geometry::closestPointTri(
ACG::Vec3d(0.383401751518, -0.044320285320, -0.729106009007),
ACG::Vec3d(0.898327171803, -0.711405336857, 0.402669787407),
ACG::Vec3d(-1.138887882233, 0.470909774303, -0.511726200581),
ACG::Vec3d(0.738806843758, 1.208429455757, -0.109056398273)
);
EXPECT_TRUE(areClose(closest_point, ACG::Vec3d(0.165861088939, 0.125222789570, -0.025220099004)));
}
}
TEST(Algorithms_ClosestPoints, closestPointTri_onEdge) {
// Closest point on edges.
{
ACG::Vec3d closest_point = ACG::Geometry::closestPointTri(
ACG::Vec3d(2.194746255875, 0.654435634613, 1.605020284653),
ACG::Vec3d(0.898327171803, -0.711405336857, 0.402669787407),
ACG::Vec3d(-1.138887882233, 0.470909774303, -0.511726200581),
ACG::Vec3d(0.738806843758, 1.208429455757, -0.109056398273)
);
EXPECT_TRUE(areClose(closest_point, ACG::Vec3d(0.826052171821, 0.158427751505, 0.170818395715)));
}
{
ACG::Vec3d closest_point = ACG::Geometry::closestPointTri(
ACG::Vec3d(-1.639497995377, -1.687432765961, 0.645231306553),
ACG::Vec3d(0.898327171803, -0.711405336857, 0.402669787407),
ACG::Vec3d(-1.138887882233, 0.470909774303, -0.511726200581),
ACG::Vec3d(0.738806843758, 1.208429455757, -0.109056398273)
);
EXPECT_TRUE(areClose(closest_point, ACG::Vec3d(-0.312445889897, -0.008722876212, -0.140780953244)));
}
{
ACG::Vec3d closest_point = ACG::Geometry::closestPointTri(
ACG::Vec3d(-0.954960584641, 3.141639709473, -0.399959266186),
ACG::Vec3d(0.898327171803, -0.711405336857, 0.402669787407),
ACG::Vec3d(-1.138887882233, 0.470909774303, -0.511726200581),
ACG::Vec3d(0.738806843758, 1.208429455757, -0.109056398273)
);
EXPECT_TRUE(areClose(closest_point, ACG::Vec3d(-0.091698979114, 0.882223932862, -0.287157561834)));
}
{
ACG::Vec3d closest_point = ACG::Geometry::closestPointTri(
ACG::Vec3d(-0.326786577702, -0.595147013664, -0.012022850104),
ACG::Vec3d(0.898327171803, -0.711405336857, 0.402669787407),
ACG::Vec3d(-1.138887882233, 0.470909774303, -0.511726200581),
ACG::Vec3d(0.738806843758, 1.208429455757, -0.109056398273)
);
EXPECT_TRUE(areClose(closest_point, ACG::Vec3d(-0.062953975601, -0.153517634035, -0.028797485905)));
}
}
TEST(Algorithms_ClosestPoints, closestPointTri_onCorner) {
{
ACG::Vec3d closest_point = ACG::Geometry::closestPointTri(
ACG::Vec3d(-1.840421676636, 0.351687341928, -1.691396117210),
ACG::Vec3d(0.898327171803, -0.711405336857, 0.402669787407),
ACG::Vec3d(-1.138887882233, 0.470909774303, -0.511726200581),
ACG::Vec3d(0.738806843758, 1.208429455757, -0.109056398273)
);
EXPECT_TRUE(areClose(closest_point, ACG::Vec3d(-1.138887882233, 0.470909774303, -0.511726200581)));
}
{
ACG::Vec3d closest_point = ACG::Geometry::closestPointTri(
ACG::Vec3d(1.548038601875, 1.783731102943, -0.995657980442),
ACG::Vec3d(0.898327171803, -0.711405336857, 0.402669787407),
ACG::Vec3d(-1.138887882233, 0.470909774303, -0.511726200581),
ACG::Vec3d(0.738806843758, 1.208429455757, -0.109056398273)
);
EXPECT_TRUE(areClose(closest_point, ACG::Vec3d(0.738806843758, 1.208429455757, -0.109056398273)));
}
{
ACG::Vec3d closest_point = ACG::Geometry::closestPointTri(
ACG::Vec3d(1.674694657326, -1.574745774269, -0.140889823437),
ACG::Vec3d(0.898327171803, -0.711405336857, 0.402669787407),
ACG::Vec3d(-1.138887882233, 0.470909774303, -0.511726200581),
ACG::Vec3d(0.738806843758, 1.208429455757, -0.109056398273)
);
EXPECT_TRUE(areClose(closest_point, ACG::Vec3d(0.898327171803, -0.711405336857, 0.402669787407)));
}
}
TEST(Algorithms_ClosestPoints, closestPointTri_degenerate) {
{
ACG::Vec3d closest_point = ACG::Geometry::closestPointTri(
ACG::Vec3d(0.379400968552, -0.866840600967, -1.375681400299),
ACG::Vec3d(-2.827600002289, -1.685648560524, -0.758169531822),
ACG::Vec3d(-1.744661808014, -0.029072359204, -0.470070630312),
ACG::Vec3d(-0.661723732948, 1.627503752708, -0.181971758604)
);
EXPECT_TRUE(areClose(closest_point, ACG::Vec3d(-1.568279320469, 0.240740866643, -0.423146806300)));
}
{
ACG::Vec3d closest_point = ACG::Geometry::closestPointTri(
ACG::Vec3d(0.842265009880, 3.628707885742, -0.395066857338),
ACG::Vec3d(-2.827600002289, -1.685648560524, -0.758169531822),
ACG::Vec3d(-1.744661808014, -0.029072359204, -0.470070630312),
ACG::Vec3d(-0.661723732948, 1.627503752708, -0.181971758604)
);
EXPECT_TRUE(areClose(closest_point, ACG::Vec3d(-0.661723732948, 1.627503752708, -0.181971758604)));
}
{
ACG::Vec3d closest_point = ACG::Geometry::closestPointTri(
ACG::Vec3d(0.842265009880, 3.628707885742, -0.395066857338),
ACG::Vec3d(-1.744661808014, -0.029072359204, -0.470070600510),
ACG::Vec3d(-1.744661808014, -0.029072359204, -0.470070630312),
ACG::Vec3d(-0.661723732948, 1.627503752708, -0.181971758604)
);
EXPECT_TRUE(areClose(closest_point, ACG::Vec3d(-0.661723732948, 1.627503752708, -0.181971758604)));
}
{
ACG::Vec3d closest_point = ACG::Geometry::closestPointTri(
ACG::Vec3d(-3.731231689453, -2.141752481461, -0.150896072388),
ACG::Vec3d(-1.744661808014, -0.029072359204, -0.470070600510),
ACG::Vec3d(-1.744661808014, -0.029072359204, -0.470070630312),
ACG::Vec3d(-0.661723732948, 1.627503752708, -0.181971758604)
);
EXPECT_TRUE(areClose(closest_point, ACG::Vec3d(-1.744661808014, -0.029072359204, -0.470070600510)));
}
{
ACG::Vec3d closest_point = ACG::Geometry::closestPointTri(
ACG::Vec3d(-0.966588973999, 0.534245491028, 0.345366060734),
ACG::Vec3d(-1.744661808014, -0.029072359204, -0.470070600510),
ACG::Vec3d(-1.744661808014, -0.029072359204, -0.470070630312),
ACG::Vec3d(-0.661723732948, 1.627503752708, -0.181971758604)
);
EXPECT_TRUE(areClose(closest_point, ACG::Vec3d(-1.200293249127, 0.803651109932, -0.325249806970)));
}
{
ACG::Vec3d closest_point = ACG::Geometry::closestPointTri(
ACG::Vec3d(-0.966588973999, 0.534245491028, 0.345366060734),
ACG::Vec3d(-1.744661808014, -0.029072359204, -0.470070600510),
ACG::Vec3d(-1.744661808014, -0.029072359204, -0.470070630312),
ACG::Vec3d(-1.744661808014, -0.029072403908, -0.470070600510)
);
EXPECT_TRUE(areClose(closest_point, ACG::Vec3d(-1.744661808014, -0.029072359204, -0.470070600510)));
}
}
} /* namespace */
#include <gtest/gtest.h>
#include <ACG/Math/Matrix3x3T.hh>
#include "MatrixTestHelper.hh"
namespace {
template<class Scalar>
class Matrix3x3Test: public testing::Test {
public:
Matrix3x3Test() {}
virtual ~Matrix3x3Test() {}
typedef typename ACG::Matrix3x3T<Scalar> Matrix3x3;
};
typedef testing::Types<double, float> Implementations;
TYPED_TEST_CASE(Matrix3x3Test, Implementations);
TYPED_TEST(Matrix3x3Test, access) {
using Matrix3x3 = typename Matrix3x3Test<TypeParam>::Matrix3x3;
Matrix3x3 m {{