英文:
Triangulate faces while preserving custom data in CGAL
问题
我有一个多面体,它使用自定义的 Polyhedron_items_3
类来向结构的面添加自定义数据。例如:
typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
typedef Kernel::Point_3 Point_3;
typedef Kernel::Vector_3 Vector_3;
typedef Kernel::Plane_3 Plane_3;
template <class Refs, class Traits>
struct TFace : public CGAL::Polyhedron_items_3::Face_wrapper<Refs, Traits>::Face {
std::array<double, 8> my_data;
TFace() {}
TFace(const Plane_3& p) : CGAL::Polyhedron_items_3::Face_wrapper<Refs, Traits>::Face(p) {}
};
struct CustomPolyhedronItems : public CGAL::Polyhedron_items_3 {
template <class Refs, class Traits>
struct Face_wrapper
{
typedef typename Traits::Plane_3 Plane;
typedef TFace<Refs, Plane> Face;
};
};
typedef CGAL::Polyhedron_3<Kernel, CustomPolyhedronItems> Polyhedron;
typedef boost::graph_traits<Polyhedron>::vertex_descriptor vertex_descriptor;
typedef boost::graph_traits<Polyhedron>::face_descriptor face_descriptor;
这可以让我为多面体的每个面分配自定义数据(上面的 my_data
数组)。
然而,像 CGAL::Polygon_mesh_processing::triangulate_faces
这样的操作会生成新的面。经测试,似乎新生成的面没有复制来自被分割的面的数据,因此 my_data
不会被保留。
为了测试,我创建了一个简单的立方体(6个四边形),并在每个面上添加了自定义数据,然后通过 triangulate_faces
运行,检查自定义数据。一半的三角形保留了原始数据,另一半都被置为零。
是否可能告诉 triangulate_faces
在生成新的面时复制我的自定义数据?例如,如果一个四边形被转换为两个三角形,那么这些三角形应该具有与原始四边形相同的数据。
此外,如果可能的话,是否也可以通过 corefine_and_compute_union
或类似的重新网格化操作来实现类似的效果?
编辑:
如果这不清楚,这里使用法线快速说明了问题,取代了 my_data
。一半的三角形具有正确的法线,但另一半是错误的,因为它们都被置为零:
显然,在法线的情况下,我可以重新计算它们。但对于我的自定义数据,这是不可能的。我需要确保在三角化(和核准联合)时保留它。
英文:
I have a Polyhedron that uses a custom Polyhedron_items_ 3
class to add custom data to the faces of the structure. For example:
typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
typedef Kernel::Point_3 Point_3;
typedef Kernel::Vector_3 Vector_3;
typedef Kernel::Plane_3 Plane_3;
template <class Refs, class Traits>
struct TFace : public CGAL::Polyhedron_items_3::Face_wrapper<Refs,Traits>::Face {
std::array<double, 8> my_data;
TFace() {}
TFace(const Plane_3& p) : CGAL::Polyhedron_items_3::Face_wrapper<Refs,Traits>::Face(p) {}
};
struct CustomPolyhedronItems : public CGAL::Polyhedron_items_3 {
template <class Refs, class Traits>
struct Face_wrapper
{
typedef typename Traits::Plane_3 Plane;
typedef TFace<Refs, Plane> Face;
};
};
typedef CGAL::Polyhedron_3<Kernel, CustomPolyhedronItems> Polyhedron;
typedef boost::graph_traits<Polyhedron>::vertex_descriptor vertex_descriptor;
typedef boost::graph_traits<Polyhedron>::face_descriptor face_descriptor;
This works, and allows me to assign custom data (the my_data
array above) to each face of a Polyhedron.
However, an operation like CGAL::Polygon_mesh_processing::triangulate_faces
will generate new faces. Upon testing, it seems that the newly generated faces do not copy over the data from the face that was split, so my_data
is not preserved.
To test, I created a simple cube (6 quads) with custom data on every face, ran it through triangulate_faces
, and checked the custom data. Half of the triangles retained the original data, the other half were all zeroed.
Is it possible to tell triangulate_faces
to copy my custom data when generating new faces? E.g. if a quad is converted into two triangles, then those triangles should have the same data as the original quad.
Also, if it is possible, would it also be possible to accomplish something similar with corefine_and_compute_union
or something like a remesh operation?
EDIT:
In case that wasn't clear, here's a quick illustration of the problem using normals in place of my_data
. Half of the triangles have correct normals, but the other half are wrong since they're zeroed:
Obviously, in the case of normals I can just recalculate them. But for my custom data, that's not possible. I need to make sure I preserve it when triangulating (and corefine union)
答案1
得分: 1
以下是翻译好的部分:
"To complement the answer from Stéphane Laurent:"
"另外,如果可能的话,是否也可以通过 corefine_and_compute_union 或类似的 remesh 操作来实现类似的功能?"
"PMP's Boolean operations functions have a similar visitor mechanism:"
"PMP 的布尔运算函数具有类似的访问者机制:"
"Here is the concept describing what your visitor must provide to be used in functions such as PMP::corefine_and_compute_boolean_operations() or PMP::clip()."
"这里是描述访问者必须提供的概念,以便在诸如 PMP::corefine_and_compute_boolean_operations() 或 PMP::clip() 等函数中使用。"
"As in my other comment, I would advise searching the CGAL code base for usages of these functions with a visitor, to have an example."
"与我在另一条评论中提到的一样,我建议在 CGAL 代码库中搜索使用访问者的这些函数的用法,以获得示例。"
英文:
To complement the answer from Stéphane Laurent:
> Also, if it is possible, would it also be possible to accomplish something similar with corefine_and_compute_union or something like a remesh operation?
PMP's Boolean operations functions have a similar visitor mechanism:
Here is the concept describing what your visitor must provide to be used in functions such as PMP::corefine_and_compute_boolean_operations() or PMP::clip().
As in my other comment, I would advise searching the CGAL code base for usages of these functions with a visitor, to have an example.
答案2
得分: 0
你需要使用一个三角形访问者。不幸的是,我几个月前做过这个,我不记得所有的细节了。请注意,我的三角形网格不仅具有面颜色属性,还具有面标量属性。
struct TriangulateVisitor :
public PMP::Triangulate_faces::Default_visitor<EMesh3>
{
void before_subface_creations(face_descriptor fsplit) {
*ofaceindex = fsplit;
}
void after_subface_created(face_descriptor fnew) {
(*fmap).insert(std::make_pair(fnew, *ofaceindex));
}
TriangulateVisitor()
: fmap(new MapBetweenFaces()),
ofaceindex(new face_descriptor())
{}
std::shared_ptr<MapBetweenFaces> fmap;
std::shared_ptr<face_descriptor> ofaceindex;
};
其中
typedef std::map<face_descriptor, face_descriptor> MapBetweenFaces;
和
void triangulateMesh(EMesh3& mesh) {
MaybeFcolorMap fcolormap_ =
copy_prop<face_descriptor, std::string, EK>(mesh, "f:color");
const bool hasFcolors = fcolormap_.second;
MaybeFscalarMap fscalarmap_ =
copy_prop<face_descriptor, double, EK>(mesh, "f:scalar");
const bool hasFscalars = fscalarmap_.second;
removeProperties(mesh, {"v:normal"});
TriangulateVisitor vis;
const bool success =
PMP::triangulate_faces(mesh, CGAL::parameters::visitor(vis));
if(!success) {
Rcpp::stop("Triangulation has failed.");
}
if(hasFcolors) {
MapBetweenFaces fmap = *(vis.fmap);
Fcolors_map fcolors =
mesh.add_property_map<face_descriptor, std::string>(
"f:color", ""
).first;
for(EMesh3::Face_index fi: mesh.faces()) {
fcolors[fi] = fcolormap_.first[fmap[fi]];
}
}
if(hasFscalars) {
MapBetweenFaces fmap = *(vis.fmap);
Fscalars_map fscalars =
mesh.add_property_map<face_descriptor, double>(
"f:scalar", nan("")
).first;
for(EMesh3::Face_index fi: mesh.faces()) {
fscalars[fi] = fscalarmap_.first[fmap[fi]];
}
}
}
告诉我这是否清楚。
英文:
You have to use a Triangle Visitor. Unfortunately, I did that a couple of months ago and I don't remember everything. Note that my triangle mesh has not only face colors properties, but also face scalars.
struct TriangulateVisitor :
public PMP::Triangulate_faces::Default_visitor<EMesh3>
{
void before_subface_creations(face_descriptor fsplit) {
*ofaceindex = fsplit;
}
void after_subface_created(face_descriptor fnew) {
(*fmap).insert(std::make_pair(fnew, *ofaceindex));
}
TriangulateVisitor()
: fmap(new MapBetweenFaces()),
ofaceindex(new face_descriptor())
{}
std::shared_ptr<MapBetweenFaces> fmap;
std::shared_ptr<face_descriptor> ofaceindex;
};
where
typedef std::map<face_descriptor, face_descriptor> MapBetweenFaces;
and
void triangulateMesh(EMesh3& mesh) {
MaybeFcolorMap fcolormap_ =
copy_prop<face_descriptor, std::string, EK>(mesh, "f:color");
const bool hasFcolors = fcolormap_.second;
MaybeFscalarMap fscalarmap_ =
copy_prop<face_descriptor, double, EK>(mesh, "f:scalar");
const bool hasFscalars = fscalarmap_.second;
removeProperties(mesh, {"v:normal"});
TriangulateVisitor vis;
const bool success =
PMP::triangulate_faces(mesh, CGAL::parameters::visitor(vis));
if(!success) {
Rcpp::stop("Triangulation has failed.");
}
if(hasFcolors) {
MapBetweenFaces fmap = *(vis.fmap);
Fcolors_map fcolors =
mesh.add_property_map<face_descriptor, std::string>(
"f:color", ""
).first;
for(EMesh3::Face_index fi: mesh.faces()) {
fcolors[fi] = fcolormap_.first[fmap[fi]];
}
}
if(hasFscalars) {
MapBetweenFaces fmap = *(vis.fmap);
Fscalars_map fscalars =
mesh.add_property_map<face_descriptor, double>(
"f:scalar", nan("")
).first;
for(EMesh3::Face_index fi: mesh.faces()) {
fscalars[fi] = fscalarmap_.first[fmap[fi]];
}
}
}
Say me whether this is clear.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论