improve concept

This commit is contained in:
Sébastien Loriot 2023-11-20 11:28:50 +01:00
parent 730bbba98b
commit 37fb95b5cd
7 changed files with 48 additions and 45 deletions

View File

@ -16,6 +16,7 @@ class PMPSizingField{
public: public:
/// @name Types /// @name Types
/// These types are used for the documentation of the functions of the concept and not needed implementation wise.
/// @{ /// @{
/// Vertex descriptor type /// Vertex descriptor type
@ -38,26 +39,28 @@ typedef unspecified_type FT;
/// @name Functions /// @name Functions
/// @{ /// @{
/// a function that returns the sizing value at `v`. /// returns the sizing value at `v` (used during tangential relaxation).
FT at(const vertex_descriptor v) const; FT at(const vertex_descriptor v, const PolygonMesh& pmesh) const;
/// a function controlling edge split and edge collapse, /// returns the ratio of the current edge squared length and the local target edge squared length between
/// returning the ratio of the current edge length and the local target edge length between /// the points of `va` and `vb` in case the current edge is too long, and `std::nullopt` otherwise
/// the points of `va` and `vb` in case the current edge is too long, and `std::nullopt` otherwise. /// (used for triggering edge splits and preventing some edge collapses).
std::optional<FT> is_too_long(const vertex_descriptor va, std::optional<FT> is_too_long(const vertex_descriptor va,
const vertex_descriptor vb) const; const vertex_descriptor vb,
const PolygonMesh& pmesh) const;
/// a function controlling edge collapse by returning the ratio of the squared length of `h` and the /// returns the ratio of the squared length of `h` and the
/// local target edge length if it is too short, and `std::nullopt` otherwise. /// local target edge squared length if it is too short, and `std::nullopt` otherwise
/// (used for triggering edge collapses).
std::optional<FT> is_too_short(const halfedge_descriptor h, std::optional<FT> is_too_short(const halfedge_descriptor h,
const PolygonMesh& pmesh) const; const PolygonMesh& pmesh) const;
/// a function returning the location of the split point of the edge of `h`. /// returns the position of the new vertex created when splitting the edge of `h`.
Point_3 split_placement(const halfedge_descriptor h, Point_3 split_placement(const halfedge_descriptor h,
const PolygonMesh& pmesh) const; const PolygonMesh& pmesh) const;
/// a function that updates the sizing field value at the vertex `v`. /// function called after the addition of the split vertex `v` in `pmesh`.
void update(const vertex_descriptor v, void register_split_vertex(const vertex_descriptor v,
const PolygonMesh& pmesh); const PolygonMesh& pmesh);
/// @} /// @}

View File

@ -19,14 +19,12 @@ struct My_sizing_field
{ {
double min_size, max_size; double min_size, max_size;
double ymin, ymax; double ymin, ymax;
const Mesh& mesh;
My_sizing_field(double min_size, double max_size, double ymin, double ymax, const Mesh& mesh) My_sizing_field(double min_size, double max_size, double ymin, double ymax)
: min_size(min_size) : min_size(min_size)
, max_size(max_size) , max_size(max_size)
, ymin(ymin) , ymin(ymin)
, ymax(ymax) , ymax(ymax)
, mesh(mesh)
{} {}
double at(K::Point_3 p) const double at(K::Point_3 p) const
@ -34,10 +32,11 @@ struct My_sizing_field
double y=p.y(); double y=p.y();
return CGAL::square( (y-ymin)/(ymax-ymin) * (min_size - max_size) + max_size ); return CGAL::square( (y-ymin)/(ymax-ymin) * (min_size - max_size) + max_size );
} }
double at(const Mesh::Vertex_index v) const { return at(mesh.point(v)); } double at(const Mesh::Vertex_index v, const Mesh& mesh) const { return at(mesh.point(v)); }
std::optional<double> is_too_long(const Mesh::Vertex_index va, std::optional<double> is_too_long(const Mesh::Vertex_index va,
const Mesh::Vertex_index vb) const const Mesh::Vertex_index vb,
const Mesh& mesh) const
{ {
// TODO: no mesh as parameters? // TODO: no mesh as parameters?
K::Point_3 mp = CGAL::midpoint(mesh.point(va), mesh.point(vb)); K::Point_3 mp = CGAL::midpoint(mesh.point(va), mesh.point(vb));
@ -49,7 +48,7 @@ struct My_sizing_field
} }
std::optional<double> is_too_short(const Mesh::Halfedge_index h, std::optional<double> is_too_short(const Mesh::Halfedge_index h,
const Mesh&) const const Mesh& mesh) const
{ {
K::Point_3 mp = CGAL::midpoint(mesh.point(source(h, mesh)), mesh.point(target(h, mesh))); K::Point_3 mp = CGAL::midpoint(mesh.point(source(h, mesh)), mesh.point(target(h, mesh)));
double sql_at = at(mp); double sql_at = at(mp);
@ -60,12 +59,12 @@ struct My_sizing_field
} }
K::Point_3 split_placement(const Mesh::Halfedge_index h, K::Point_3 split_placement(const Mesh::Halfedge_index h,
const Mesh&) const const Mesh& mesh) const
{ {
return CGAL::midpoint(mesh.point(source(h, mesh)), mesh.point(target(h, mesh))); return CGAL::midpoint(mesh.point(source(h, mesh)), mesh.point(target(h, mesh)));
} }
void update(const Mesh::Vertex_index, const Mesh&) {} void register_split_vertex(const Mesh::Vertex_index, const Mesh&) {}
}; };
@ -83,7 +82,7 @@ int main(int argc, char* argv[])
<< " (" << num_faces(mesh) << " faces)..." << std::endl; << " (" << num_faces(mesh) << " faces)..." << std::endl;
CGAL::Bbox_3 bb = PMP::bbox(mesh); CGAL::Bbox_3 bb = PMP::bbox(mesh);
My_sizing_field sizing_field(0.1, 30, bb.ymin(), bb.ymax(), mesh); My_sizing_field sizing_field(0.1, 30, bb.ymin(), bb.ymax());
unsigned int nb_iter = 5; unsigned int nb_iter = 5;
PMP::isotropic_remeshing( PMP::isotropic_remeshing(

View File

@ -213,13 +213,13 @@ private:
} }
public: public:
FT at(const vertex_descriptor v) const FT at(const vertex_descriptor v, const PolygonMesh& /* pmesh */) const
{ {
CGAL_assertion(get(m_vertex_sizing_map, v)); CGAL_assertion(get(m_vertex_sizing_map, v));
return get(m_vertex_sizing_map, v); return get(m_vertex_sizing_map, v);
} }
std::optional<FT> is_too_long(const vertex_descriptor va, const vertex_descriptor vb) const std::optional<FT> is_too_long(const vertex_descriptor va, const vertex_descriptor vb, const PolygonMesh& /* pmesh */) const
{ {
const FT sqlen = sqlength(va, vb); const FT sqlen = sqlength(va, vb);
FT sqtarg_len = CGAL::square(4./3. * (CGAL::min)(get(m_vertex_sizing_map, va), FT sqtarg_len = CGAL::square(4./3. * (CGAL::min)(get(m_vertex_sizing_map, va),
@ -251,7 +251,7 @@ public:
get(m_vpmap, source(h, pmesh))); get(m_vpmap, source(h, pmesh)));
} }
void update(const vertex_descriptor v, const PolygonMesh& pmesh) void register_split_vertex(const vertex_descriptor v, const PolygonMesh& pmesh)
{ {
// calculating it as the average of two vertices on other ends // calculating it as the average of two vertices on other ends
// of halfedges as updating is done during an edge split // of halfedges as updating is done during an edge split

View File

@ -102,12 +102,12 @@ private:
} }
public: public:
FT at(const vertex_descriptor /* v */) const FT at(const vertex_descriptor /* v */, const PolygonMesh& /* pmesh */) const
{ {
return m_size; return m_size;
} }
std::optional<FT> is_too_long(const vertex_descriptor va, const vertex_descriptor vb) const std::optional<FT> is_too_long(const vertex_descriptor va, const vertex_descriptor vb, const PolygonMesh& /* pmesh */) const
{ {
const FT sqlen = sqlength(va, vb); const FT sqlen = sqlength(va, vb);
if (sqlen > m_sq_long) if (sqlen > m_sq_long)
@ -133,7 +133,7 @@ public:
get(m_vpmap, source(h, pmesh))); get(m_vpmap, source(h, pmesh)));
} }
void update(const vertex_descriptor /* v */, const PolygonMesh& /* pmesh */) void register_split_vertex(const vertex_descriptor /* v */, const PolygonMesh& /* pmesh */)
{} {}
private: private:

View File

@ -246,7 +246,7 @@ namespace internal {
get(ecmap, e) || get(ecmap, e) ||
get(fpm, face(h,pmesh))!=get(fpm, face(opposite(h,pmesh),pmesh)) ) get(fpm, face(h,pmesh))!=get(fpm, face(opposite(h,pmesh),pmesh)) )
{ {
if (sizing.is_too_long(source(h, pmesh), target(h, pmesh))) if (sizing.is_too_long(source(h, pmesh), target(h, pmesh), pmesh))
{ {
return false; return false;
} }
@ -400,7 +400,7 @@ namespace internal {
for(edge_descriptor e : edge_range) for(edge_descriptor e : edge_range)
{ {
const halfedge_descriptor he = halfedge(e, mesh_); const halfedge_descriptor he = halfedge(e, mesh_);
std::optional<double> sqlen = sizing.is_too_long(source(he, mesh_), target(he, mesh_)); std::optional<double> sqlen = sizing.is_too_long(source(he, mesh_), target(he, mesh_), mesh_);
if(sqlen != std::nullopt) if(sqlen != std::nullopt)
long_edges.emplace(he, sqlen.value()); long_edges.emplace(he, sqlen.value());
} }
@ -433,16 +433,16 @@ namespace internal {
std::cout << " refinement point : " << refinement_point << std::endl; std::cout << " refinement point : " << refinement_point << std::endl;
#endif #endif
//update sizing field with the new point //update sizing field with the new point
sizing.update(vnew, mesh_); sizing.register_split_vertex(vnew, mesh_);
//check sub-edges //check sub-edges
//if it was more than twice the "long" threshold, insert them //if it was more than twice the "long" threshold, insert them
std::optional<double> sqlen_new = sizing.is_too_long(source(hnew, mesh_), target(hnew, mesh_)); std::optional<double> sqlen_new = sizing.is_too_long(source(hnew, mesh_), target(hnew, mesh_), mesh_);
if(sqlen_new != std::nullopt) if(sqlen_new != std::nullopt)
long_edges.emplace(hnew, sqlen_new.value()); long_edges.emplace(hnew, sqlen_new.value());
const halfedge_descriptor hnext = next(hnew, mesh_); const halfedge_descriptor hnext = next(hnew, mesh_);
sqlen_new = sizing.is_too_long(source(hnext, mesh_), target(hnext, mesh_)); sqlen_new = sizing.is_too_long(source(hnext, mesh_), target(hnext, mesh_), mesh_);
if (sqlen_new != std::nullopt) if (sqlen_new != std::nullopt)
long_edges.emplace(hnext, sqlen_new.value()); long_edges.emplace(hnext, sqlen_new.value());
@ -500,7 +500,7 @@ namespace internal {
if (!is_split_allowed(e)) if (!is_split_allowed(e))
continue; continue;
const halfedge_descriptor he = halfedge(e, mesh_); const halfedge_descriptor he = halfedge(e, mesh_);
std::optional<double> sqlen = sizing.is_too_long(source(he, mesh_), target(he, mesh_)); std::optional<double> sqlen = sizing.is_too_long(source(he, mesh_), target(he, mesh_), mesh_);
if(sqlen != std::nullopt) if(sqlen != std::nullopt)
long_edges.emplace(halfedge(e, mesh_), sqlen.value()); long_edges.emplace(halfedge(e, mesh_), sqlen.value());
} }
@ -550,16 +550,16 @@ namespace internal {
halfedge_added(hnew_opp, status(opposite(he, mesh_))); halfedge_added(hnew_opp, status(opposite(he, mesh_)));
//update sizing field with the new point //update sizing field with the new point
sizing.update(vnew, mesh_); sizing.register_split_vertex(vnew, mesh_);
//check sub-edges //check sub-edges
//if it was more than twice the "long" threshold, insert them //if it was more than twice the "long" threshold, insert them
std::optional<double> sqlen_new = sizing.is_too_long(source(hnew, mesh_), target(hnew, mesh_)); std::optional<double> sqlen_new = sizing.is_too_long(source(hnew, mesh_), target(hnew, mesh_), mesh_);
if(sqlen_new != std::nullopt) if(sqlen_new != std::nullopt)
long_edges.emplace(hnew, sqlen_new.value()); long_edges.emplace(hnew, sqlen_new.value());
const halfedge_descriptor hnext = next(hnew, mesh_); const halfedge_descriptor hnext = next(hnew, mesh_);
sqlen_new = sizing.is_too_long(source(hnext, mesh_), target(hnext, mesh_)); sqlen_new = sizing.is_too_long(source(hnext, mesh_), target(hnext, mesh_), mesh_);
if (sqlen_new != std::nullopt) if (sqlen_new != std::nullopt)
long_edges.emplace(hnext, sqlen_new.value()); long_edges.emplace(hnext, sqlen_new.value());
@ -580,7 +580,7 @@ namespace internal {
if (snew == PATCH) if (snew == PATCH)
{ {
std::optional<double> sql = sizing.is_too_long(source(hnew2, mesh_), target(hnew2, mesh_)); std::optional<double> sql = sizing.is_too_long(source(hnew2, mesh_), target(hnew2, mesh_), mesh_);
if(sql != std::nullopt) if(sql != std::nullopt)
long_edges.emplace(hnew2, sql.value()); long_edges.emplace(hnew2, sql.value());
} }
@ -603,7 +603,7 @@ namespace internal {
if (snew == PATCH) if (snew == PATCH)
{ {
std::optional<double> sql = sizing.is_too_long(source(hnew2, mesh_), target(hnew2, mesh_)); std::optional<double> sql = sizing.is_too_long(source(hnew2, mesh_), target(hnew2, mesh_), mesh_);
if (sql != std::nullopt) if (sql != std::nullopt)
long_edges.emplace(hnew2, sql.value()); long_edges.emplace(hnew2, sql.value());
} }
@ -747,7 +747,7 @@ namespace internal {
for(halfedge_descriptor ha : halfedges_around_target(va, mesh_)) for(halfedge_descriptor ha : halfedges_around_target(va, mesh_))
{ {
vertex_descriptor va_i = source(ha, mesh_); vertex_descriptor va_i = source(ha, mesh_);
std::optional<double> sqha = sizing.is_too_long(vb, va_i); std::optional<double> sqha = sizing.is_too_long(vb, va_i, mesh_);
if (sqha != std::nullopt) if (sqha != std::nullopt)
{ {
collapse_ok = false; collapse_ok = false;

View File

@ -60,13 +60,14 @@ public:
typedef typename K::FT FT; typedef typename K::FT FT;
public: public:
virtual FT at(const vertex_descriptor v) const = 0; virtual FT at(const vertex_descriptor v, const PolygonMesh&) const = 0;
virtual std::optional<FT> is_too_long(const vertex_descriptor va, virtual std::optional<FT> is_too_long(const vertex_descriptor va,
const vertex_descriptor vb) const = 0; const vertex_descriptor vb,
const PolygonMesh&) const = 0;
virtual std::optional<FT> is_too_short(const halfedge_descriptor h, virtual std::optional<FT> is_too_short(const halfedge_descriptor h,
const PolygonMesh& pmesh) const = 0; const PolygonMesh& pmesh) const = 0;
virtual Point_3 split_placement(const halfedge_descriptor h, const PolygonMesh& pmesh) const = 0; virtual Point_3 split_placement(const halfedge_descriptor h, const PolygonMesh& pmesh) const = 0;
virtual void update(const vertex_descriptor v, const PolygonMesh& pmesh) = 0; virtual void register_split_vertex(const vertex_descriptor v, const PolygonMesh& pmesh) = 0;
}; };

View File

@ -288,9 +288,9 @@ void tangential_relaxation(const VertexRange& vertices,
const double tri_area = gt_area(get(vpm, v), get(vpm, v1), get(vpm, v2)); const double tri_area = gt_area(get(vpm, v), get(vpm, v1), get(vpm, v2));
const double face_weight = tri_area const double face_weight = tri_area
/ (1. / 3. * (sizing.at(v) / (1. / 3. * (sizing.at(v, tm)
+ sizing.at(v1) + sizing.at(v1, tm)
+ sizing.at(v2))); + sizing.at(v2, tm)));
weight += face_weight; weight += face_weight;
const Point_3 centroid = gt_centroid(get(vpm, v), get(vpm, v1), get(vpm, v2)); const Point_3 centroid = gt_centroid(get(vpm, v), get(vpm, v1), get(vpm, v2));