CGAL邊折疊edge_collapse的問題

使用edge_collapse對一個模型簡化,之后回收垃圾,collect_garbage

處理之前的頂點和三角形數量:

number_of_vertices: 955730 ?number_of_faces: 1903410
num_vertices: 955730 ?num_faces: 1903410


處理之后的頂點和三角形數量:
number_of_vertices: 479309 ?number_of_faces: 950633
num_vertices: 479309 ?num_faces: 950633
可以看到頂點數和三角形數都減少了

然后遍歷每個三角形,計算每個點的法線:

for (auto face : mesh.faces()) {

?? ??? ?auto h = mesh.halfedge(face);
?? ??? ?auto v0 = mesh.target(h);
?? ??? ?auto v1 = mesh.target(mesh.next(h));
?? ??? ?auto v2 = mesh.target(mesh.prev(h));

}

奇怪的事情發生了,當讀取到ID為5623的面時,其第一個頂點v0 值為v953550,超出了number_of_vertices的大小,引起程序崩潰

測試程序如下:
?


#include <CGAL/Simple_cartesian.h>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
#include <CGAL/IO/polygon_mesh_io.h>
#include <CGAL/IO/STL.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Polygon_2.h>#include <CGAL/Polygon_mesh_processing/compute_normal.h>#include <CGAL/Aff_transformation_3.h>
#include <CGAL/Aff_transformation_2.h>#include <CGAL/IO/polygon_soup_io.h>
#include <CGAL/Polygon_mesh_processing/repair_polygon_soup.h>#include <CGAL/Filtered_kernel/internal/Static_filters/Is_degenerate_3.h>#include <CGAL/Surface_mesh.h>
#include <CGAL/Polygon_mesh_processing/repair.h>
#include <CGAL/Polygon_mesh_processing/stitch_borders.h>
#include <CGAL/Polygon_mesh_processing/repair_degeneracies.h>
#include <CGAL/Polygon_mesh_processing/remesh.h>#include <CGAL/Surface_mesh_simplification/edge_collapse.h>
#include <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/LindstromTurk_cost.h>
#include <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Edge_count_stop_predicate.h>
#include <CGAL/Surface_mesh_simplification/Edge_collapse_visitor_base.h>#include <CGAL/Simple_cartesian.h>  // 或者你使用的其他內核
#include <CGAL/Surface_mesh.h>
#include <CGAL/Polygon_mesh_processing/compute_normal.h>typedef std::function<void(std::size_t, std::size_t)> _callback;namespace SMS = CGAL::Surface_mesh_simplification;typedef std::function<void(std::size_t, std::size_t)> _callback;typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef CGAL::Exact_predicates_exact_constructions_kernel Exact_kernel;
typedef K::Point_2 Point2;
typedef K::Point_3 Point3;
typedef K::Triangle_3 Triangle3;
typedef K::Vector_3 Vector3;
typedef K::Vector_2 Vector2;
typedef K::Plane_3 Plane3;
typedef CGAL::Bbox_3 Box3;
typedef CGAL::Bbox_2 Box2;
typedef K::Segment_2 Segment2;
typedef K::Segment_3 Segment3;
typedef CGAL::Polygon_2<K> Polygon2;
typedef CGAL::Surface_mesh<Point3> Mesh;
typedef std::shared_ptr<Mesh>	Mesh_ptr;typedef boost::graph_traits<Mesh> GT;
typedef typename GT::face_descriptor face_descriptor;
typedef typename GT::edge_descriptor edge_descriptor;
typedef typename GT::halfedge_descriptor halfedge_descriptor;
typedef typename GT::vertex_descriptor vertex_descriptor;
typedef typename GT::face_iterator face_iterator;
typedef typename GT::edge_iterator edge_iterator;
typedef typename GT::vertex_iterator vertex_iterator;void compute_vertex_normals_manual(const Mesh& mesh,std::vector<Vector3>& vertex_normals) {// 初始化頂點法向量為0int size = mesh.num_vertices();vertex_normals.resize(mesh.num_vertices(), Vector3(0, 0, 0));std::cout << "vertex_normals size " << size << std::endl;// 用于記錄每個頂點相鄰的面數std::vector<int> vertex_face_count(mesh.num_vertices(), 0);// 遍歷所有面片std::ofstream ofs("compute_vertex_normals_manual.txt");ofs << "num_faces " << (int)mesh.num_faces() << std::endl;ofs << "num_vertices " << (int)mesh.num_vertices() << std::endl;for (auto face : mesh.faces()) {ofs << face.id() << std::endl;if (5623 == face.id()) ofs << "a" << std::endl;if (5623 == face.id()) {bool del = mesh.is_removed(face);ofs << "is_removed " << del << std::endl;}// 獲取面片的三個頂點auto h = mesh.halfedge(face);if (5623 == face.id()) ofs << "halfedge " << h << std::endl;if (5623 == face.id()) ofs << "halfedge is_removed " << mesh.is_removed(h)<< std::endl;auto v0 = mesh.target(h);auto v1 = mesh.target(mesh.next(h));auto v2 = mesh.target(mesh.prev(h));if (5623 == face.id()) ofs << "mesh.point" << std::endl;if (5623 == face.id()) ofs << v0 << " " << v1 << " " << v2 << std::endl;if (5623 == face.id()) {/*bool del1 = mesh.is_removed(v0);bool del2 = mesh.is_removed(v1);bool del3 = mesh.is_removed(v2);ofs << "is_removed del1 " << del1 << std::endl;ofs << "is_removed del2 " << del2 << std::endl;ofs << "is_removed del3 " << del3 << std::endl;
*/}// 計算面片法向量Point3 p0 = mesh.point(v0);Point3 p1 = mesh.point(v1);Point3 p2 = mesh.point(v2);if (5623 == face.id()) ofs << "p0" << p0.x() << " " << p0.y() << " " << p0.z() << std::endl;if (5623 == face.id()) ofs << "p1" << p1.x() << " " << p1.y() << " " << p1.z() << std::endl;if (5623 == face.id()) ofs << "p2" << p2.x() << " " << p2.y() << " " << p2.z() << std::endl;if (5623 == face.id()) ofs << "c" << std::endl;Vector3 edge1 = p1 - p0;Vector3 edge2 = p2 - p0;Vector3 face_normal = CGAL::cross_product(edge1, edge2);if (5623 == face.id()) ofs << "d" << std::endl;// 歸一化面片法向量(可選)double len = CGAL::sqrt(face_normal.squared_length());if (len > 0) face_normal = face_normal / len;if (5623 == face.id()) ofs << "e" << std::endl;// 累加到頂點法向量vertex_normals[v0.idx()] = vertex_normals[v0.idx()] + face_normal;vertex_normals[v1.idx()] = vertex_normals[v1.idx()] + face_normal;vertex_normals[v2.idx()] = vertex_normals[v2.idx()] + face_normal;if (5623 == face.id()) ofs << "f" << std::endl;vertex_face_count[v0.idx()]++;vertex_face_count[v1.idx()]++;vertex_face_count[v2.idx()]++;if (5623 == face.id()) ofs << "g" << std::endl;}// 平均法向量并歸一化for (size_t i = 0; i < vertex_normals.size(); ++i) {if (vertex_face_count[i] > 0) {vertex_normals[i] = vertex_normals[i] / vertex_face_count[i];double len = CGAL::sqrt(vertex_normals[i].squared_length());if (len > 0) vertex_normals[i] = vertex_normals[i] / len;}}
}int main()
{typedef CGAL::Point_3<CGAL::Simple_cartesian<float>> STL_point;typedef CGAL::array<int, 3> STL_tringle;std::cout << "begin" << std::endl;std::string file_path = "F:\\WORK\\STL\\Print-test\\test-bug\\1\\Groot_Planter_-_v2Groot_Plante.stl";std::vector<STL_point> points;std::vector<STL_tringle> faces;Mesh_ptr mesh = std::make_shared<Mesh>();//box_top = Box3();try {CGAL::IO::read_polygon_soup(file_path, points, faces);/*STL_FILE::read_STL(_file_path, points, faces, [&](std::size_t a, std::size_t b) {aggregator.updateSectionProgress(a, b);});
*/CGAL::Polygon_mesh_processing::repair_polygon_soup(points, faces);std::cout << "repair_polygon_soup" << std::endl;std::vector <Mesh::vertex_index>vHandles;vHandles.reserve(points.size());mesh->reserve(points.size(), points.size() + faces.size(), faces.size());for (auto& pt : points) {auto vh = mesh->add_vertex(Point3((double)pt[0], (double)pt[1], (double)pt[2]));vHandles.push_back(vh);//box_top += Box3(pt[0], pt[1], pt[2], pt[0], pt[1], pt[2]);}int i = 0;for (auto& tri : faces) {int v0 = tri[0];int v1 = tri[1];int v2 = tri[2];if (v0 == v1 || v1 == v2 || v0 == v2)continue;auto vh0 = vHandles[v0];auto vh1 = vHandles[v1];auto vh2 = vHandles[v2];auto fh = mesh->add_face(vh0, vh1, vh2);if (!fh.is_valid()) {Point3 p0 = mesh->point(vh0);Point3 p1 = mesh->point(vh1);Point3 p2 = mesh->point(vh2);auto vh3 = mesh->add_vertex(p0);auto vh4 = mesh->add_vertex(p1);auto vh5 = mesh->add_vertex(p2);mesh->add_face(vh3, vh4, vh5);}++i;}}catch (const std::exception& e) {std::cerr << "load_STL" << e.what() << std::endl;}Mesh& _mesh = *mesh;size_t total_edges = _mesh.number_of_edges();CGAL::Surface_mesh_simplification::Edge_count_stop_predicate<Mesh> stop(total_edges / 2 - 1); // 目標邊數std::cout << "************start***************" << std::endl;//num_vertices 955730 number_of_vertices 479307std::cout << "number_of_vertices: " << _mesh.number_of_vertices() << "  number_of_faces: " << _mesh.number_of_faces() << std::endl;std::cout << "num_vertices: " << _mesh.num_vertices() << "  num_faces: " << _mesh.num_faces() << std::endl;SMS::edge_collapse(_mesh, stop);if (!CGAL::is_valid(_mesh)) {//CGAL::Polygon_mesh_processing::remove_degenerate_faces(_mesh);//CGAL::Polygon_mesh_processing::stitch_borders(_mesh);}std::cout << "************edge_collapse***************"   << std::endl;//num_vertices 955730 number_of_vertices 479307std::cout << "number_of_vertices: " << _mesh.number_of_vertices() << "  number_of_faces: " << _mesh.number_of_faces() << std::endl;std::cout << "num_vertices: " << _mesh.num_vertices() << "  num_faces: " << _mesh.num_faces() << std::endl;_mesh.collect_garbage();//_mesh.collect_garbage();std::cout << "************collect_garbage***************" << std::endl;//num_vertices 955730 number_of_vertices 479307std::cout << "number_of_vertices: " << _mesh.number_of_vertices() << "  number_of_faces: " << _mesh.number_of_faces() << std::endl;std::cout << "num_vertices: " << _mesh.num_vertices() << "  num_faces: " << _mesh.num_faces() << std::endl;////auto vertex_normals = _mesh.add_property_map<vertex_descriptor, Vector3>("v:normal").first;//CGAL::Polygon_mesh_processing::compute_vertex_normals(_mesh, vertex_normals);//std::vector<Vector3> vertex_normals;compute_vertex_normals_manual(_mesh, vertex_normals);std::cout << "compute_vertex_normals" << std::endl;
}

日志:

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/77450.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/77450.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/77450.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

用c語言實現——順序隊列支持用戶輸入交互、入隊、出隊、查找、遍歷、計算隊列長度等功能。確定判斷判滿的方法為:犧牲一個存儲單元方式

一、知識介紹 1.基本原理 在順序隊列中&#xff0c;我們使用一個固定大小的數組來存儲隊列中的元素&#xff0c;并使用兩個指針&#xff08;front 和 rear&#xff09;來分別表示隊頭和隊尾的位置。 隊列為空的條件&#xff1a;front rear 隊列滿的條件&#xff1a;rear 1…

JVM 系列:JVM 內存結構深度解析

你點贊了嗎&#xff1f;你關注了嗎&#xff1f;每天分享干貨好文。 高并發解決方案與架構設計。 海量數據存儲和性能優化。 通用框架/組件設計與封裝。 如何設計合適的技術架構&#xff1f; 如何成功轉型架構設計與技術管理&#xff1f; 在競爭激烈的大環境下&#xff0c…

手機上的APN是什么,該怎么設置

網上說改個APN就可以讓網速快幾倍&#xff0c;那到底APN是個什么東西&#xff0c;真的能讓網速快幾倍嗎&#xff1f; APN的作用 網絡連接基礎&#xff1a;APN&#xff08;接入點名稱&#xff09;是手機連接移動網絡的“橋梁”&#xff0c;負責識別運營商網絡類型&#xff08;…

微服務治理與可觀測性

服務注冊與發現 核心功能 服務實例動態變化&#xff1a;實例可能因擴縮容、故障或遷移導致IP變動。服務依賴解耦&#xff1a;調用方無需硬編碼服務地址&#xff0c;降低耦合度。負載均衡&#xff1a;自動選擇健康實例&#xff0c;提升系統可用性。 核心組件 服務注冊中心&am…

嵌入式linux系統中內存管理的方法與實現

第一:linux內核管理詳解圖形 第二:Linux內存管理詳細分析 深入剖析Linux內核內存管理 作為嵌入式系統開發者,理解Linux內核的內存管理對于開發高效、穩定的系統至關重要。在這篇文章中,我們將詳細解析Linux內核如何劃分物理內存和虛擬內存,頁表、MMU(內存管理單元)與TL…

【dataframe顯示不全問題】打開一個行列超多的excel轉成df之后行列顯示不全

出現問題如下圖&#xff1a; 解決方案&#xff5e; display.width解決列顯示不全 pd.set_option(display.max_columns,1000) pd.set_option(display.width, 1000) pd.set_option(display.max_colwidth,1000) pd.set_option(display.max_rows,1000)

Linux——Shell編程之正則表達式與文本處理器(筆記)

目錄 基礎正則表達式 1:基礎正則表達式示例 &#xff08;4&#xff09;查找任意一個字符“.”與重新字符“*” &#xff08;5&#xff09;查找連續字符范圍“{ }” 文本處理器 一、sed工具 二、awk工具 &#xff08;1&#xff09;按行輸出文本 &#xff08;2&#xff0…

OpenHarmony系統-源碼下載,環境搭建,編譯,燒錄,調試

獲取源碼 以OpenHarmony5.0.3為例 repo init -u https://gitee.com/openharmony/manifest -b OpenHarmony-5.0.3-Release --no-repo-verify repo sync -c repo forall -c git lfs pull搭建環境 安裝必要的工具和命令 apt-get install -y apt-utils binutils bison flex bc …

Vue3 本地打包啟動白屏解決思路!! !

“為什么我訪問 http://127.0.0.1:5501/index.html 白屏&#xff0c;刪了 index.html 再訪問 / 就又活過來了&#xff1f;” —— 你的項目與 SPA 路由的“宮斗大戲” 一、問題復現 場景 本地通過 VSCode Live Server&#xff08;或其他靜態服務器&#xff09;啟動了打包后的 V…

數字人(2):數字人技術全景透視(2025演進版)

隨著人工智能技術的迅猛發展,數字人技術發展也是一日千里。站在當下,著眼未來,我們一起在回眸透視過去的基礎上,一起共同眺望數字人技術的未來。 一、數字人技術體系重構 我們可以用三維定義對數字人技術進行框架重構 維度 技術內涵 典型特征 物理層 人體數字化建模技術 …

小剛說C語言刷題——1035 判斷成績等級

1.題目描述 輸入某學生成績&#xff0c;如果 86分以上(包括 86分&#xff09;則輸出 VERY GOOD &#xff0c;如果在 60到 85之間的則輸出 GOOD (包括 60和 85)&#xff0c;小于 60 的則輸出 BAD。 輸入 輸入只有一行&#xff0c;包括 1個整數。 輸出 輸出只有一行&#xf…

React-在使用map循環數組渲染列表時須指定唯一且穩定值的key

在渲染列表的時候&#xff0c;我們須給組件或者元素分配一個唯一值的key, key是一個特殊的屬性&#xff0c;不會最終加在元素上面&#xff0c;也無法通過props.key來獲取&#xff0c;僅在react內部使用。react中的key本質是服務于diff算法, 它的默認值是null, 在diff算法過程中…

Zookeeper的通知機制是什么?

大家好&#xff0c;我是鋒哥。今天分享關于【Zookeeper的通知機制是什么&#xff1f;】面試題。希望對大家有幫助&#xff1b; Zookeeper的通知機制是什么&#xff1f; 1000道 互聯網大廠Java工程師 精選面試題-Java資源分享網 Zookeeper 的通知機制是其核心特性之一&#xf…

【LangChain實戰】構建下一代智能問答系統:從RAG架構到生產級優化

打破傳統問答系統的次元壁 當ChatGPT在2022年掀起AI革命時&#xff0c;開發者們很快發現一個殘酷現實&#xff1a;通用大模型在專業領域的表現如同拿著地圖的盲人&#xff0c;既無法理解企業私有數據&#xff0c;也無法保證事實準確性。這催生了RAG&#xff08;檢索增強生成&a…

UDS中功能尋址可以請求多幀數據嘛?當ECU響應首幀后,診斷儀是通過物理尋址發送流控幀嘛?

文章目錄 1. 前言??1.1 功能尋址是否支持請求多幀數據?1.2 ECU發送首幀(FF)后,診斷儀如何發送流控幀(FC)?1.3 協議依據(ISO 14229-1)1.4 實際應用注意事項總結1. 前言?? 在UDS(Unified Diagnostic Services)協議中,功能尋址與物理尋址的使用規則以及多幀數據傳…

PHP異常處理__Throwable

在 PHP 里&#xff0c;Throwable 是一個極為關鍵的接口&#xff0c;自 PHP 7 起被引入。它為錯誤和異常處理構建了一個統一的框架。下面會詳細介紹 Throwable 的相關內容。 1. 基本概念 Throwable 是 Exception 和 Error 的父接口。在 PHP 7 之前&#xff0c;異常&#xff08…

無需訓練的具身導航探索!TRAVEL:零樣本視覺語言導航中的檢索與對齊

作者&#xff1a; Navid Rajabi, Jana Kosecka 單位&#xff1a;喬治梅森大學計算機科學系 論文標題&#xff1a;TRAVEL: Training-Free Retrieval and Alignment for Vision-and-Language Navigation 論文鏈接&#xff1a;https://arxiv.org/pdf/2502.07306 主要貢獻 提出…

Vue3+Vite+TypeScript+Element Plus開發-22.客制Table組件

系列文檔目錄 Vue3ViteTypeScript安裝 Element Plus安裝與配置 主頁設計與router配置 靜態菜單設計 Pinia引入 Header響應式菜單縮展 Mockjs引用與Axios封裝 登錄設計 登錄成功跳轉主頁 多用戶動態加載菜單 Pinia持久化 動態路由 -動態增加路由 動態路由-動態刪除…

Java讀取JSON文件并將其中元素轉為JSON對象輸出

&#x1f91f;致敬讀者 &#x1f7e9;感謝閱讀&#x1f7e6;笑口常開&#x1f7ea;生日快樂?早點睡覺 &#x1f4d8;博主相關 &#x1f7e7;博主信息&#x1f7e8;博客首頁&#x1f7eb;專欄推薦&#x1f7e5;活動信息 文章目錄 Java讀取JSON文件并將其中元素轉為JSON對象輸…

Spring Boot自動配置原理深度解析:從條件注解到spring.factories

大家好&#xff01;今天我們來深入探討Spring Boot最神奇的特性之一——自動配置(Auto-configuration)。這個功能讓Spring Boot如此受歡迎&#xff0c;因為它大大簡化了我們的開發工作。讓我們一起來揭開它的神秘面紗吧&#xff01;&#x1f440; &#x1f31f; 什么是自動配置…