從 Delaunay 轉向優化的耳切演算法
地圖渲染需要將多邊形切割為三角形,因為 GPU 僅能填充三角形。Globus Software 原先使用受限 Delaunay 三角剖分器,處理華沙馬佐夫舍省離線地圖第 13 級縮放的 374 萬個多邊形需耗時 2.93 秒(單核心 M4 Pro)。
開發團隊發現,對於平面填充而言,三角形的形狀品質並非關鍵,且近半數多邊形頂點少於四個,無需複雜切割。因此團隊改用耳切演算法(Ear Clipping),並透過逐步提交程式碼的方式重建該演算法,每一步驟均在相同資料集上進行基準測試。
關鍵優化技術與效能提升過程
基礎的耳切實作將處理時間降至 1.12 秒。隨後團隊實施多項優化:僅檢查可能阻擋耳朵形成的凹點(dents),將時間降至 882 毫秒;針對無凹點的凸多邊形直接生成三角形帶,省去測試步驟;以及使用桶排序索引凹點以減少掃描範圍。
進一步的優化包括移除分支預測失敗風險高的迴圈結構,改用無分支計數方式判斷點是否在三角形內,並僅對標記為命中的凹點進行精確檢查。這些步驟最終將總處理時間降至 489 毫秒,較原始 Delaunay 方法快 6 倍。
值得注意的是,對於頂點超過 257 個的大型多邊形,耳切演算法的成本隨大小平方增長,因此在最後階段仍比 Delaunay 慢(199 ms vs 90 ms),但整體平均效能因多數小型多邊形的加速而大幅提升。
瀏覽器環境下的比較測試
開發者將 earstrip 與 MapLibre 和 Mapbox GL 使用的 earcut.js 3.2.4 進行比較。在原生 C++ 環境中,earstrip 比 earcut.hpp 快 14%。但在瀏覽器環境中,差異更為顯著:使用 V8 引擎時,earstrip 的 WebAssembly 版本比 earcut.js 快 1.4 倍;使用 JavaScriptCore 時則快 1.6 倍。
若採用直接呼叫方式將多邊形資料傳入 WebAssembly 模組記憶體,避免逐個多邊形的 JavaScript 呼叫開銷,earstrip 的速度可達 earcut.js 的 1.7 至 2.1 倍。測試顯示,earcut.hpp 編譯為 WebAssembly 後效能損失主要來自其尋找耳朵的主迴圈,而非記憶體分配器問題。
在正確性方面,對於耳切無法精確處理的多邊形,earcut.js 生成的三角形與偶奇填充規則的平均像素差異為 31%,而 earstrip 僅為 0.15%。
處理非簡單多邊形與極端情況的回退機制
地圖資料常因網格化捨入導致多邊形自相交或頂點合併,這可能違反耳切演算法的前提條件。當演算法無法找到耳朵時,會嘗試移除無面積的角點重試;若仍失敗,則自動回退至受限 Delaunay 三角剖分處理該多邊形。
對於包含大量孔洞的多邊形(例如超過 128 個孔),耳切演算法因需掃描整個邊界以尋找橋接線而效率低落。測試顯示,一個擁有 11,675 個孔洞的多邊形,earstrip 需 606 毫秒,而 Delaunay 僅需 17 毫秒。因此系統會自動將這類多邊形導向 Delaunay 處理。
在 Globus Software 的世界地圖瓦片中,包含 56,472 個多邊形的測試集上,earstrip 總耗時 459 毫秒,而 earcut.hpp 需 2,892 毫秒。




