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

如何在CGAL 2D Arrangement中便捷使用CGAL::simplify?

CGAL 2D Arrangement 边序列简化实现方案

目前CGAL并没有提供直接一键简化所有由2度顶点分隔边序列的工具函数,你需要手动完成提取、简化、替换这三步,但可以通过一套连贯的流程高效实现,不用完全拆分重组整个Arrangement。以下是具体步骤和代码示例:

核心步骤

1. 识别并提取2度顶点连接的边序列

遍历Arrangement中的所有顶点,筛选出度数为2的内部顶点(排除无穷远顶点),然后追踪这些顶点连接的边,形成连续的折线边链。注意要避免重复处理同一个边链。

2. 提取折线点并执行简化

将边链的起点、所有中间2度顶点的坐标、终点组成点序列,调用CGAL::simplify函数传入距离阈值完成简化。建议使用平方距离阈值,避免开方运算提升效率。

3. 替换原边序列为简化后的折线

先删除原边链的所有边,再移除孤立的2度顶点,最后将简化后的折线插入到Arrangement中,确保拓扑结构正确。

代码示例

// 假设使用Exact_predicates_exact_constructions_kernel作为核心内核
typedef CGAL::Exact_predicates_exact_constructions_kernel K;
typedef CGAL::Arrangement_2<K> Arrangement;
typedef Arrangement::Vertex_handle Vertex_handle;
typedef Arrangement::Halfedge_handle Halfedge_handle;
typedef CGAL::Point_2<K> Point_2;
typedef std::vector<Point_2> Point_sequence;

// 提取单个2度顶点所属的完整边链
std::vector<Halfedge_handle> extract_edge_chain(Vertex_handle start_v) {
    std::vector<Halfedge_handle> chain;
    Halfedge_handle current_he = start_v->incident_halfedges();
    
    do {
        chain.push_back(current_he);
        // 下一个顶点是当前边的目标点的对边的下一条边
        Vertex_handle next_v = current_he->target();
        if (next_v->degree() != 2) break; // 遇到非2度顶点,终止链
        current_he = next_v->incident_halfedges()->opposite()->next();
    } while (current_he->source() != start_v); // 回到起点则闭合链
    
    return chain;
}

// 执行Arrangement简化的主函数
void simplify_arrangement_edges(Arrangement& arr, double distance_threshold) {
    std::vector<std::vector<Halfedge_handle>> all_chains;
    std::unordered_set<Vertex_handle> processed_vertices;

    // 第一步:收集所有未处理的2度顶点对应的边链
    for (auto v_it = arr.vertices_begin(); v_it != arr.vertices_end(); ++v_it) {
        Vertex_handle v = v_it;
        if (v->degree() == 2 && !v->is_at_infinity() && processed_vertices.find(v) == processed_vertices.end()) {
            auto chain = extract_edge_chain(v);
            all_chains.push_back(chain);
            // 标记链中所有顶点为已处理
            for (auto he : chain) {
                processed_vertices.insert(he->source());
                processed_vertices.insert(he->target());
            }
        }
    }

    // 第二步+第三步:处理每条边链
    for (auto& chain : all_chains) {
        // 提取原始点序列
        Point_sequence original_pts;
        original_pts.push_back(chain.front()->source()->point());
        for (auto he : chain) {
            original_pts.push_back(he->target()->point());
        }

        // 简化折线:使用平方距离阈值避免开方
        Point_sequence simplified_pts;
        const K::FT squared_threshold = CGAL::square(distance_threshold);
        CGAL::simplify(original_pts.begin(), original_pts.end(),
                       std::back_inserter(simplified_pts),
                       CGAL::Squared_distance_d<K>(), squared_threshold);

        // 删除原边链的所有边
        std::vector<Vertex_handle> orphaned_vertices;
        for (auto he : chain) {
            if (!he->is_fictitious()) {
                // 提前收集可能孤立的顶点
                if (he->source()->degree() == 2) orphaned_vertices.push_back(he->source());
                if (he->target()->degree() == 2) orphaned_vertices.push_back(he->target());
                arr.remove_edge(he);
            }
        }

        // 删除孤立的2度顶点(边删除后度数变为0)
        for (auto v : orphaned_vertices) {
            if (v->degree() == 0) {
                arr.remove_vertex(v);
            }
        }

        // 插入简化后的折线
        if (simplified_pts.size() >= 2) {
            // 区分闭合多边形和开放折线
            if (simplified_pts.front() == simplified_pts.back()) {
                CGAL::insert_non_intersecting_curve(arr, CGAL::Polygon_2<K>(simplified_pts.begin(), simplified_pts.end()));
            } else {
                CGAL::insert_non_intersecting_curve(arr, simplified_pts.begin(), simplified_pts.end());
            }
        }
    }
}

注意事项

  • 处理边链时要标记已处理的顶点,避免重复处理同一序列。
  • 删除边和顶点的顺序很重要:先删边,再删失去所有边的孤立顶点。
  • 插入简化后的折线时,要区分是闭合多边形还是开放折线,调用对应的insert_non_intersecting_curve重载版本,确保拓扑正确。
  • 如果你的Arrangement使用了其他内核或特征类,需要相应调整代码中的类型定义。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 19:37:48