mirror of https://github.com/CGAL/cgal
Fix of issue 8213 by consider length of a vector being zero if enough small, define diff_of_product in a specific file
This commit is contained in:
parent
b54a2eab1a
commit
95b4eba11e
|
|
@ -0,0 +1,60 @@
|
||||||
|
// Copyright (c) 2025 GeometryFactory (France). All rights reserved.
|
||||||
|
//
|
||||||
|
// This file is part of CGAL (www.cgal.org).
|
||||||
|
//
|
||||||
|
// $URL$
|
||||||
|
// $Id$
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
|
||||||
|
//
|
||||||
|
// Author(s) : Mael Rouxel-Labbé
|
||||||
|
//
|
||||||
|
#ifndef CGAL_CARTESIAN_CROSSPRODUCT_H
|
||||||
|
#define CGAL_CARTESIAN_CROSSPRODUCT_H
|
||||||
|
|
||||||
|
#include <CGAL/license/Surface_mesh_simplification.h>
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
namespace CGAL {
|
||||||
|
|
||||||
|
// a*b - c*d
|
||||||
|
// The next two functions are from https://stackoverflow.com/questions/63665010/accurate-floating-point-computation-of-the-sum-and-difference-of-two-products
|
||||||
|
static double diff_of_products_kahan(const double a, const double b, const double c, const double d)
|
||||||
|
{
|
||||||
|
double w = d * c;
|
||||||
|
double e = std::fma(c, -d, w);
|
||||||
|
double f = std::fma(a, b, -w);
|
||||||
|
return f + e;
|
||||||
|
}
|
||||||
|
|
||||||
|
static double diff_of_products_cht(const double a, const double b, const double c, const double d)
|
||||||
|
{
|
||||||
|
double p1 = a * b;
|
||||||
|
double p2 = c * d;
|
||||||
|
double e1 = std::fma (a, b, -p1);
|
||||||
|
double e2 = std::fma (c, -d, p2);
|
||||||
|
double r = p1 - p2;
|
||||||
|
double e = e1 + e2;
|
||||||
|
return r + e;
|
||||||
|
}
|
||||||
|
|
||||||
|
static double diff_of_products(const double a, const double b, const double c, const double d)
|
||||||
|
{
|
||||||
|
// return a*b - c*d;
|
||||||
|
// the next two are equivalent in results and speed
|
||||||
|
return diff_of_products_kahan(a, b, c, d);
|
||||||
|
// return diff_of_products_cht(a, b, c, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OFT>
|
||||||
|
static OFT diff_of_products(const OFT& a, const OFT& b, const OFT& c, const OFT& d)
|
||||||
|
{
|
||||||
|
return a*b - c*d;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace CGAL
|
||||||
|
|
||||||
|
#endif // CGAL_CARTESIAN_CROSSPRODUCT_H //
|
||||||
|
// EOF //
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
#include <CGAL/Null_matrix.h>
|
#include <CGAL/Null_matrix.h>
|
||||||
#include <CGAL/number_utils.h>
|
#include <CGAL/number_utils.h>
|
||||||
#include <CGAL/Vector_3.h>
|
#include <CGAL/Vector_3.h>
|
||||||
|
#include <CGAL/Cartesian/CrossProduct.h>
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
|
|
@ -219,6 +220,19 @@ std::optional< MatrixC33<R> > inverse_matrix(const MatrixC33<R>& m)
|
||||||
|
|
||||||
if(! CGAL_NTS is_zero(det))
|
if(! CGAL_NTS is_zero(det))
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// RT c00 = diff_of_products(m.r1().y(),m.r2().z(),m.r2().y(),m.r1().z()) / det;
|
||||||
|
// RT c01 = diff_of_products(m.r2().y(),m.r0().z(),m.r0().y(),m.r2().z()) / det;
|
||||||
|
// RT c02 = diff_of_products(m.r0().y(),m.r1().z(),m.r1().y(),m.r0().z()) / det;
|
||||||
|
|
||||||
|
// RT c10 = diff_of_products(m.r2().x(),m.r1().z(),m.r1().x(),m.r2().z()) / det;
|
||||||
|
// RT c11 = diff_of_products(m.r0().x(),m.r2().z(),m.r2().x(),m.r0().z()) / det;
|
||||||
|
// RT c12 = diff_of_products(m.r1().x(),m.r0().z(),m.r0().x(),m.r1().z()) / det;
|
||||||
|
|
||||||
|
// RT c20 = diff_of_products(m.r1().x(),m.r2().y(),m.r2().x(),m.r1().y()) / det;
|
||||||
|
// RT c21 = diff_of_products(m.r2().x(),m.r0().y(),m.r0().x(),m.r2().y()) / det;
|
||||||
|
// RT c22 = diff_of_products(m.r0().x(),m.r1().y(),m.r1().x(),m.r0().y()) / det;
|
||||||
|
|
||||||
RT c00 = (m.r1().y()*m.r2().z() - m.r1().z()*m.r2().y()) / det;
|
RT c00 = (m.r1().y()*m.r2().z() - m.r1().z()*m.r2().y()) / det;
|
||||||
RT c01 = (m.r2().y()*m.r0().z() - m.r0().y()*m.r2().z()) / det;
|
RT c01 = (m.r2().y()*m.r0().z() - m.r0().y()*m.r2().z()) / det;
|
||||||
RT c02 = (m.r0().y()*m.r1().z() - m.r1().y()*m.r0().z()) / det;
|
RT c02 = (m.r0().y()*m.r1().z() - m.r1().y()*m.r0().z()) / det;
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
#include <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Edge_profile.h>
|
#include <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Edge_profile.h>
|
||||||
|
|
||||||
#include <CGAL/Cartesian/MatrixC33.h>
|
#include <CGAL/Cartesian/MatrixC33.h>
|
||||||
|
#include <CGAL/Cartesian/CrossProduct.h>
|
||||||
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
@ -101,6 +102,8 @@ private :
|
||||||
void extract_triangle_data();
|
void extract_triangle_data();
|
||||||
void extract_boundary_data();
|
void extract_boundary_data();
|
||||||
|
|
||||||
|
double maxBb;
|
||||||
|
|
||||||
void add_boundary_preservation_constraints(const Boundary_data_vector& aBdry);
|
void add_boundary_preservation_constraints(const Boundary_data_vector& aBdry);
|
||||||
void add_volume_preservation_constraints(const Triangle_data_vector& triangles);
|
void add_volume_preservation_constraints(const Triangle_data_vector& triangles);
|
||||||
void add_boundary_and_volume_optimization_constraints(const Boundary_data_vector& aBdry,
|
void add_boundary_and_volume_optimization_constraints(const Boundary_data_vector& aBdry,
|
||||||
|
|
@ -119,42 +122,6 @@ private :
|
||||||
const Geom_traits& geom_traits() const { return mProfile.geom_traits(); }
|
const Geom_traits& geom_traits() const { return mProfile.geom_traits(); }
|
||||||
const TM& surface() const { return mProfile.surface(); }
|
const TM& surface() const { return mProfile.surface(); }
|
||||||
|
|
||||||
#if 0
|
|
||||||
// a*b - c*d
|
|
||||||
// The next two functions are from https://stackoverflow.com/questions/63665010/accurate-floating-point-computation-of-the-sum-and-difference-of-two-products
|
|
||||||
static double diff_of_products_kahan(const double a, const double b, const double c, const double d)
|
|
||||||
{
|
|
||||||
double w = d * c;
|
|
||||||
double e = std::fma(c, -d, w);
|
|
||||||
double f = std::fma(a, b, -w);
|
|
||||||
return f + e;
|
|
||||||
}
|
|
||||||
|
|
||||||
static double diff_of_products_cht(const double a, const double b, const double c, const double d)
|
|
||||||
{
|
|
||||||
double p1 = a * b;
|
|
||||||
double p2 = c * d;
|
|
||||||
double e1 = std::fma (a, b, -p1);
|
|
||||||
double e2 = std::fma (c, -d, p2);
|
|
||||||
double r = p1 - p2;
|
|
||||||
double e = e1 + e2;
|
|
||||||
return r + e;
|
|
||||||
}
|
|
||||||
|
|
||||||
static double diff_of_products(const double a, const double b, const double c, const double d)
|
|
||||||
{
|
|
||||||
// the next two are equivalent in results and speed
|
|
||||||
return diff_of_products_kahan(a, b, c, d);
|
|
||||||
// return diff_of_products_cht(a, b, c, d);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename OFT>
|
|
||||||
static OFT diff_of_products(const OFT& a, const OFT& b, const OFT& c, const OFT& d)
|
|
||||||
{
|
|
||||||
return a*b - c*d;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __AVX__
|
#ifdef __AVX__
|
||||||
static Vector SL_cross_product_avx(const Vector& A, const Vector& B)
|
static Vector SL_cross_product_avx(const Vector& A, const Vector& B)
|
||||||
{
|
{
|
||||||
|
|
@ -353,12 +320,18 @@ extract_triangle_data()
|
||||||
{
|
{
|
||||||
mTriangle_data.reserve(mProfile.triangles().size());
|
mTriangle_data.reserve(mProfile.triangles().size());
|
||||||
|
|
||||||
|
//TODO for obscur reason, computing this abs_max increase running time by 10%
|
||||||
|
double abs_max;
|
||||||
for(const Triangle& tri : mProfile.triangles())
|
for(const Triangle& tri : mProfile.triangles())
|
||||||
{
|
{
|
||||||
const Point_reference p0 = get_point(tri.v0);
|
const Point_reference p0 = get_point(tri.v0);
|
||||||
const Point_reference p1 = get_point(tri.v1);
|
const Point_reference p1 = get_point(tri.v1);
|
||||||
const Point_reference p2 = get_point(tri.v2);
|
const Point_reference p2 = get_point(tri.v2);
|
||||||
|
|
||||||
|
abs_max=(std::max)({abs_max,std::abs(p0.x()),std::abs(p0.y()),std::abs(p0.z()),
|
||||||
|
std::abs(p1.x()),std::abs(p1.y()),std::abs(p1.z()),
|
||||||
|
std::abs(p2.x()),std::abs(p2.y()),std::abs(p2.z())});
|
||||||
|
|
||||||
Vector v01 = p1 - p0;
|
Vector v01 = p1 - p0;
|
||||||
Vector v02 = p2 - p0;
|
Vector v02 = p2 - p0;
|
||||||
|
|
||||||
|
|
@ -370,6 +343,7 @@ extract_triangle_data()
|
||||||
|
|
||||||
mTriangle_data.push_back(Triangle_data(lNormalV,lNormalL));
|
mTriangle_data.push_back(Triangle_data(lNormalV,lNormalL));
|
||||||
}
|
}
|
||||||
|
maxBb= abs_max;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class TM, class K>
|
template<class TM, class K>
|
||||||
|
|
@ -687,7 +661,11 @@ add_constraint_if_alpha_compatible(const Vector& Ai,
|
||||||
FT l = CGAL_NTS sqrt(slai);
|
FT l = CGAL_NTS sqrt(slai);
|
||||||
CGAL_SMS_LT_TRACE(3, " l: " << n_to_string(l));
|
CGAL_SMS_LT_TRACE(3, " l: " << n_to_string(l));
|
||||||
|
|
||||||
if(!CGAL_NTS is_zero(l))
|
// Due to double number type, l may have a small value instead of zero (example sum of the faces normals of a tetrahedra for volumic constraint)
|
||||||
|
// if bin is greater than maxBb, we consider that l is zero
|
||||||
|
CGAL_SMS_LT_TRACE(3, " error consider: " << (std::abs(bi) / (2*maxBb)));
|
||||||
|
if(l > (std::abs(bi) / (2*maxBb)))
|
||||||
|
// if(!CGAL_NTS is_zero(l))
|
||||||
{
|
{
|
||||||
Vector Ain = Ai / l;
|
Vector Ain = Ai / l;
|
||||||
FT bin = bi / l;
|
FT bin = bi / l;
|
||||||
|
|
@ -862,6 +840,7 @@ add_constraint_from_gradient(const Matrix& H,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include <CGAL/Surface_mesh.h>
|
#include <CGAL/Surface_mesh.h>
|
||||||
|
|
||||||
|
CGAL::Bbox_3 bbox_g;
|
||||||
|
double max_bbox_g;
|
||||||
#define CGAL_CHECK_EXPENSIVE
|
#define CGAL_CHECK_EXPENSIVE
|
||||||
|
|
||||||
#define CGAL_SURFACE_SIMPLIFICATION_ENABLE_TRACE 5
|
#define CGAL_SURFACE_SIMPLIFICATION_ENABLE_TRACE 5
|
||||||
|
|
@ -15,7 +17,7 @@ void Surface_simplification_external_trace(const std::string& s)
|
||||||
|
|
||||||
#include <CGAL/Surface_mesh_simplification/edge_collapse.h>
|
#include <CGAL/Surface_mesh_simplification/edge_collapse.h>
|
||||||
#include <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Bounded_normal_change_filter.h>
|
#include <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Bounded_normal_change_filter.h>
|
||||||
#include <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Bounding_box_filter.h>
|
// #include <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Bounding_box_filter.h>
|
||||||
#include <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Face_count_stop_predicate.h>
|
#include <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Face_count_stop_predicate.h>
|
||||||
#include <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/LindstromTurk_cost.h>
|
#include <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/LindstromTurk_cost.h>
|
||||||
#include <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/LindstromTurk_placement.h>
|
#include <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/LindstromTurk_placement.h>
|
||||||
|
|
@ -48,19 +50,19 @@ int main(int argc, char** argv)
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
CGAL::Bbox_3 bbox = PMP::bbox(sm);
|
auto bb=PMP::bbox(sm);
|
||||||
|
std::cout << "Bbox:" << bb << std::endl;
|
||||||
std::cout << "Input mesh has " << num_vertices(sm) << " vertices" << std::endl;
|
std::cout << "Input mesh has " << num_vertices(sm) << " vertices" << std::endl;
|
||||||
std::cout << "Input mesh has " << num_faces(sm) << " faces" << std::endl;
|
std::cout << "Input mesh has " << num_faces(sm) << " faces" << std::endl;
|
||||||
|
|
||||||
|
|
||||||
SMS::Face_count_stop_predicate<Surface_mesh> stop(1);
|
SMS::Face_count_stop_predicate<Surface_mesh> stop(1);
|
||||||
SMS::edge_collapse(
|
SMS::edge_collapse(
|
||||||
surface_mesh,
|
sm,
|
||||||
stop,
|
stop,
|
||||||
CGAL::parameters::
|
CGAL::parameters::
|
||||||
filter(SMS::Bounded_normal_change_filter<SMS::Bounding_box_filter<>>(SMS::Bounding_box_filter<>()))
|
// filter(SMS::Bounded_normal_change_filter<>()) //<SMS::Bounding_box_filter<>>(SMS::Bounding_box_filter<>()))
|
||||||
.get_cost(SMS::LindstromTurk_cost<Surface_mesh>())
|
get_cost(SMS::LindstromTurk_cost<Surface_mesh>())
|
||||||
.get_placement(SMS::LindstromTurk_placement<Surface_mesh>())
|
.get_placement(SMS::LindstromTurk_placement<Surface_mesh>())
|
||||||
);
|
);
|
||||||
CGAL::IO::write_OFF(std::cout, sm, CGAL::parameters::stream_precision(17));
|
CGAL::IO::write_OFF(std::cout, sm, CGAL::parameters::stream_precision(17));
|
||||||
|
|
@ -69,7 +71,7 @@ int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
// To be within the bounding box isn't a guarantee, but here it is a sufficient test
|
// To be within the bounding box isn't a guarantee, but here it is a sufficient test
|
||||||
// to check if things went awry
|
// to check if things went awry
|
||||||
if(!CGAL::do_overlap(bbox, sm.point(v).bbox()))
|
if(!CGAL::do_overlap(bb, sm.point(v).bbox()))
|
||||||
{
|
{
|
||||||
std::cerr << "Error: " << sm.point(v) << " is outside the initial bbox" << std::endl;
|
std::cerr << "Error: " << sm.point(v) << " is outside the initial bbox" << std::endl;
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue