/* This file is part of the Gudhi Library. The Gudhi library * (Geometric Understanding in Higher Dimensions) is a generic C++ * library for computational topology. * * Author(s): David Salinas * * Copyright (C) 2014 INRIA Sophia Antipolis-M�diterran�e (France) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifndef GARLAND_HECKBERT_ERROR_QUADRIC_H_ #define GARLAND_HECKBERT_ERROR_QUADRIC_H_ #include #include #include template class Error_quadric { private: double coeff[10]; public: Error_quadric() { clear(); } /** * Quadric corresponding to the L2 distance to the plane. * * According to the notation of Garland Heckbert, they * denote a quadric symetric matrix as : * Q = [ q11 q12 q13 q14] * [ q12 q22 q23 q24] * [ q13 q23 q33 q34] * [ q14 q24 q34 q44] * * which is represented by a vector with 10 elts that * are denoted ci for clarity with : * Q = [ c0 c1 c2 c3 ] * [ c1 c4 c5 c6 ] * [ c2 c5 c7 c8 ] * [ c3 c6 c8 c9 ] * * The constructor return the quadrics that represents * the squared distance to the plane defined by triangle p0,p1,p2 * times the area of triangle p0,p1,p2. */ Error_quadric(const Point & p0, const Point & p1, const Point & p2) { Point normal(unit_normal(p0, p1, p2)); double a = normal[0]; double b = normal[1]; double c = normal[2]; double d = -a * p0[0] - b * p0[1] - c * p0[2]; coeff[0] = a*a; coeff[1] = a*b; coeff[2] = a*c; coeff[3] = a*d; coeff[4] = b*b; coeff[5] = b*c; coeff[6] = b*d; coeff[7] = c*c; coeff[8] = c*d; coeff[9] = d*d; double area_p0p1p2 = std::sqrt(squared_area(p0, p1, p2)); for (auto& x : coeff) x *= area_p0p1p2; } inline double squared_area(const Point& p0, const Point& p1, const Point& p2) { // if (x1,x2,x3) = p1-p0 and (y1,y2,y3) = p2-p0 // then the squared area is = (u^2+v^2+w^2)/4 // with: u = x2 * y3 - x3 * y2; // v = x3 * y1 - x1 * y3; // w = x1 * y2 - x2 * y1; Point p0p1(p1 - p0); Point p0p2(p2 - p0); double A = p0p1[1] * p0p2[2] - p0p1[2] * p0p2[1]; double B = p0p1[2] * p0p2[0] - p0p1[0] * p0p2[2]; double C = p0p1[0] * p0p2[1] - p0p1[1] * p0p2[0]; return 1. / 4. * (A * A + B * B + C * C); } void clear() { for (auto& x : coeff) x = 0; } Error_quadric& operator+=(const Error_quadric& other) { if (this != &other) { for (int i = 0; i < 10; ++i) coeff[i] += other.coeff[i]; } return *this; } /** * @return The quadric quost defined by the scalar product v^T Q v where Q is the quadratic form of Garland/Heckbert */ inline double cost(const Point& point) const { double cost = coeff[0] * point.x() * point.x() + coeff[4] * point.y() * point.y() + coeff[7] * point.z() * point.z() + 2 * (coeff[1] * point.x() * point.y() + coeff[5] * point.y() * point.z() + coeff[2] * point.z() * point.x()) + 2 * (coeff[3] * point.x() + coeff[6] * point.y() + coeff[8] * point.z()) + coeff[9]; if (cost < 0) { return 0; } else { return cost; } } inline double grad_determinant() const { return coeff[0] * coeff[4] * coeff[7] - coeff[0] * coeff[5] * coeff[5] - coeff[1] * coeff[1] * coeff[7] + 2 * coeff[1] * coeff[5] * coeff[2] - coeff[4] * coeff[2] * coeff[2]; } /** * Return the point such that it minimizes the gradient of the quadric. * Det must be passed with the determinant value of the gradient (should be non zero). */ inline Point solve_linear_gradient(double det) const { return Point({ (-coeff[1] * coeff[5] * coeff[8] + coeff[1] * coeff[7] * coeff[6] + coeff[2] * coeff[8] * coeff[4] - coeff[2] * coeff[5] * coeff[6] - coeff[3] * coeff[4] * coeff[7] + coeff[3] * coeff[5] * coeff[5]) / det, (coeff[0] * coeff[5] * coeff[8] - coeff[0] * coeff[7] * coeff[6] - coeff[5] * coeff[2] * coeff[3] - coeff[1] * coeff[2] * coeff[8] + coeff[6] * coeff[2] * coeff[2] + coeff[1] * coeff[3] * coeff[7]) / det, (-coeff[8] * coeff[0] * coeff[4] + coeff[8] * coeff[1] * coeff[1] + coeff[2] * coeff[3] * coeff[4] + coeff[5] * coeff[0] * coeff[6] - coeff[5] * coeff[1] * coeff[3] - coeff[1] * coeff[2] * coeff[6]) / det }); } /** * returns the point that minimizes the quadric. * It inverses the quadric if its determinant is higher that a given threshold . * If the determinant is lower than this value the returned value is uninitialized. */ boost::optional min_cost(double scale = 1) const { // const double min_determinant = 1e-4 * scale*scale; const double min_determinant = 1e-5; boost::optional pt_res; double det = grad_determinant(); if (std::abs(det) > min_determinant) pt_res = solve_linear_gradient(det); return pt_res; } friend std::ostream& operator<<(std::ostream& stream, const Error_quadric& quadric) { stream << "\n[ " << quadric.coeff[0] << "," << quadric.coeff[1] << "," << quadric.coeff[2] << "," << quadric.coeff[3] << ";\n"; stream << " " << quadric.coeff[1] << "," << quadric.coeff[4] << "," << quadric.coeff[5] << "," << quadric.coeff[6] << ";\n"; stream << " " << quadric.coeff[2] << "," << quadric.coeff[5] << "," << quadric.coeff[7] << "," << quadric.coeff[8] << ";\n"; stream << " " << quadric.coeff[3] << "," << quadric.coeff[6] << "," << quadric.coeff[8] << "," << quadric.coeff[9] << "]"; return stream; } }; #endif // GARLAND_HECKBERT_ERROR_QUADRIC_H_