You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CGAL Remesh结果存在随机性问题:如何获得固定输出?

关于CGAL重网格结果不一致的问题

我正在使用CGAL中的Remesh函数进行重网格操作,预览结果视觉上一致,但标记面索引后发现面的顺序不同,顶点坐标也存在细微差异,且输入完全相同。

重网格结果:
重网格结果1
重网格结果2
重网格结果3

代码实现

void CGAL_Remesh(double* vert_xyz_array, size_t vert_count, double criteria_a, double criteria_b, int iteration_number, double*& newVertices, int*& vCount, int*& newFaces, int*& fCount) 
{ CDT cdt; // insert Vertex_handle

vector<Vertex_handle> cdt_Vh_Boundary;
for (int i = 0; i < vert_count; ++i)
{
    Vertex_handle vh = cdt.insert(Point(vert_xyz_array[3 * i + 0], vert_xyz_array[3 * i + 1]));
    cdt_Vh_Boundary.push_back(vh);
}
// insert Constrain
for (int i = 0; i < cdt_Vh_Boundary.size() - 1; ++i)
{
    cdt.insert_constraint(cdt_Vh_Boundary[i], cdt_Vh_Boundary[i + 1]);
}
cdt.insert_constraint(cdt_Vh_Boundary[cdt_Vh_Boundary.size() - 1], cdt_Vh_Boundary[0]);
// refine and optimize mesh
Mesher mesher(cdt);
mesher.set_criteria(Criteria(criteria_a, criteria_b));
mesher.refine_mesh();
CGAL::lloyd_optimize_mesh_2(cdt, CGAL::parameters::max_iteration_number = iteration_number);
// make index pair
vector<CDT::Vertex_handle> visitedVertices;   // collect visited vertices
map<CDT::Vertex_handle, int> indexList;      // create a map to note the index
int i = 0;
for (CDT::Vertex_iterator v_it = cdt.vertices_begin(); v_it != cdt.vertices_end(); ++v_it)
{
    CDT::Vertex_handle vh = v_it->handle();
    indexList[vh] = i;
    visitedVertices.push_back(vh);
    i++;
}
// Convert data into double array
int vNum = cdt.number_of_vertices();
newVertices = new double[vNum * 3];

i = 0;
for (CDT::Vertex_iterator vi = cdt.vertices_begin(); vi != cdt.vertices_end(); ++vi)
{
    newVertices[i] = vi->point()[0];
    i += 1;
    newVertices[i] = vi->point()[1];
    i += 1;
    newVertices[i] = 0;
    i += 1;
}
int vertexCount = vNum;
vCount = &vertexCount;
int num_face_in_domain = 0;
for (CDT::Face_iterator f_it = cdt.faces_begin(); f_it != cdt.faces_end(); ++f_it)
{
    CDT::Face_handle face = f_it;
    if (face->is_in_domain())
    {
        num_face_in_domain++;
    }
}
newFaces = new int[num_face_in_domain * 3];

i = 0;
for (CDT::Face_iterator f_it = cdt.faces_begin(); f_it != cdt.faces_end(); ++f_it)
{
    CDT::Face_handle face = f_it;
    if (face->is_in_domain())
    {
        newFaces[i] = int(indexList.find(face->vertex(0)->handle())->second);
        i += 1;
        newFaces[i] = int(indexList.find(face->vertex(1)->handle())->second);
        i += 1;
        newFaces[i] = int(indexList.find(face->vertex(2)->handle())->second);
        i += 1;
    }
}
int faceCount = num_face_in_domain;
fCount = &faceCount;
}

请问我的代码是否存在问题,或者有什么方法可以获得固定的重网格结果?
非常感谢!


问题分析与解决方法

代码存在的问题

  1. 局部变量地址返回风险:vCount = &vertexCount;和fCount = &faceCount;返回的是函数内部局部变量的地址,函数结束后局部变量会被销毁,外部访问该地址属于未定义行为,大概率引发内存错误。
  2. 遍历顺序不稳定:CGAL的vertices_begin()和faces_begin()迭代器的遍历顺序不保证固定,每次运行可能因内部数据结构的随机性(如哈希表存储顺序)导致面、顶点的输出顺序变化。

固定重网格结果的方案

  • 设置全局随机种子:CGAL部分网格算法依赖随机数,在程序初始化时调用CGAL::set_random_seed(42);(42可替换为任意固定数值),消除随机性来源。
  • 修复内存错误:将vCount和fCount改为传值逻辑,函数参数调整为int* vCount,内部直接赋值*vCount = vNum;和*fCount = num_face_in_domain;,调用方提前准备好变量接收数值。
  • 稳定索引分配:不要依赖迭代器顺序分配顶点索引,改为按顶点坐标排序后分配,或者给每个顶点绑定唯一标识,确保索引映射的一致性。
  • 控制Lloyd优化的随机性:lloyd_optimize_mesh_2的浮点计算会有微小差异,固定随机种子后可大幅降低偏差;若需要完全一致,可考虑减少迭代次数,或替换为确定性的优化策略。
  • 一致性验证逻辑:对比网格时不要直接校验索引顺序,而是通过拓扑邻接关系、顶点坐标的误差范围(如小于1e-6)来判断结果是否一致。

内容的提问来源于stack exchange,提问作者ZEBIN CHEN

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 19:04:50