2013-03-06 231 views
3

我正在嘗試使用JS Clipper對SVG路徑(包含beziers,包括二次和立方體)執行布爾操作。將SVG路徑轉換爲用於Javascript Clipper的多邊形

JS Clipper以多邊形開始,然後執行操作,然後它似乎將它們轉換回SVG路徑。

下面的函數給出了一個SVG路徑,但下面的示例以2個多邊形開始。

一個例子功能:

// Polygon Arrays are expanded for better readability 

function clip() { 
    var subj_polygons = [ 
    [{ 
     X: 10, 
     Y: 10 
    }, { 
     X: 110, 
     Y: 10 
    }, { 
     X: 110, 
     Y: 110 
    }, { 
     X: 10, 
     Y: 110 
    }], 
    [{ 
     X: 20, 
     Y: 20 
    }, { 
     X: 20, 
     Y: 100 
    }, { 
     X: 100, 
     Y: 100 
    }, { 
     X: 100, 
     Y: 20 
    }] 
    ]; 

    var clip_polygons = [ 
    [{ 
     X: 50, 
     Y: 50 
    }, { 
     X: 150, 
     Y: 50 
    }, { 
     X: 150, 
     Y: 150 
    }, { 
     X: 50, 
     Y: 150 
    }], 
    [{ 
     X: 60, 
     Y: 60 
    }, { 
     X: 60, 
     Y: 140 
    }, { 
     X: 140, 
     Y: 140 
    }, { 
     X: 140, 
     Y: 60 
    }] 
    ]; 

    var scale = 100; 
    subj_polygons = scaleup(subj_polygons, scale); 
    clip_polygons = scaleup(clip_polygons, scale); 

    var cpr = new ClipperLib.Clipper(); 
    cpr.AddPolygons(subj_polygons, ClipperLib.PolyType.ptSubject); 
    cpr.AddPolygons(clip_polygons, ClipperLib.PolyType.ptClip); 

    var subject_fillType = ClipperLib.PolyFillType.pftNonZero; 
    var clip_fillType = ClipperLib.PolyFillType.pftNonZero; 
    var clipTypes = [ClipperLib.ClipType.ctUnion]; 
    var clipTypesTexts = "Union"; 
    var solution_polygons, svg, cont = document.getElementById('svgcontainer'); 

    var i; 
    for (i = 0; i < clipTypes.length; i++) { 
    solution_polygons = new ClipperLib.Polygons(); 
    cpr.Execute(clipTypes[i], solution_polygons, subject_fillType, clip_fillType); 
    console.log(polys2path(solution_polygons, scale)); 
    } 

} 

// helper function to scale up polygon coordinates 
function scaleup(poly, scale) { 
    var i, j; 
    if (!scale) scale = 1; 
    for (i = 0; i < poly.length; i++) { 
    for (j = 0; j < poly[i].length; j++) { 
     poly[i][j].X *= scale; 
     poly[i][j].Y *= scale; 
    } 
    } 
    return poly; 
} 

// converts polygons to SVG path string 
function polys2path(poly, scale) { 
    var path = "", 
    i, j; 
    if (!scale) scale = 1; 
    for (i = 0; i < poly.length; i++) { 
    for (j = 0; j < poly[i].length; j++) { 
     if (!j) path += "M"; 
     else path += "L"; 
     path += (poly[i][j].X/scale) + ", " + (poly[i][j].Y/scale); 
    } 
    path += "Z"; 
    } 
    return path; 

} 

回答

3

一些參考。

我已經搜索了很多,但沒有找到任何可靠和開箱即用的解決方案。

SVG路徑可以由十個不同的段組成,如果我們同時考慮相對和絕對座標,則路徑可以包含20個。它們在路徑元素的d屬性中表示爲字母:相對值爲mhvlcqastz,絕對值爲MHVLCQASTZ。每個都有不同的屬性,a(橢圓弧)是最複雜的。最可用和最靈活的類型是c(立方貝塞爾曲線),因爲它可以以相當高的精度代表所有其他類型,如以下示例所示:http://jsbin.com/oqojan/32http://jsbin.com/oqojan/42

Raphael JS庫具有Path2Curve功能,它可以將所有路徑段轉換爲三次曲線,並且它還可以處理複雜的弧到三次轉換。不幸的是,它有一個bug,所以它不能處理所有可能的路徑段組合,但幸運的是有一個固定版本的庫:http://jsbin.com/oqojan/32/edit(查看Javascript窗口)。

當所有路徑段都轉換爲三次曲線時,它們可以轉換爲單獨的線段。有幾種方法,並且最好似乎是an adaptive recursive subdivision method,它在曲線的急轉彎處產生更多的線段並且在曲線的其他部分產生更少的線段以實現曲線保真度和低段數的平衡以最大化渲染速度,但不幸的是,無法處理所有共線情況。我成功地轉換AntiGrain的方法Javascript和補充預裂功能,其將在局部極值(一階導數根)曲線,之後的AntiGrain方法也處理所有可能的線的情況下:

共線水平:http://jsbin.com/ivomiq/6
集不同的情況:http://jsbin.com/ivomiq/7
隨機:http://jsbin.com/ivomiq/8
共線轉動:http://jsbin.com/ivomiq/9

所有上述樣品具有在彼此的頂部上的兩個路徑來顯示在自適應算法可能錯誤:紅色曲線是使用已經分裂ry緩慢的蠻力方法,綠色方法使用AntiGrain方法分割。如果您看不到紅色,AntiGrain的方法approximate()-function按預期工作。好吧,現在我們已經修復了拉斐爾並修復了AntiGrain。如果我們結合這兩種方法,我們可以創建一個函數,將ANY svg路徑元素轉換爲多邊形(單個或多個子多邊形)。我不是100%確定這是最好還是最快的方法,但應該可以使用。當然最好的是本地瀏覽器實現...

+0

無論多麼複雜,此解決方案都適用於任何形狀嗎?由於多邊形轉換的路徑,我已經放棄嘗試使用您的庫。我確實設法從Phrogz使用這種方法:https://gist.github.com/Phrogz/845901轉換爲只有一個大問題的多邊形。我的用戶應該繪製非常非常複雜的彎曲形狀,必須進行布爾運算,而不會損失任何曲線上的保真度。這需要超過800個採樣所需的多邊形,這在大多數情況下甚至不能用Phrogz解決方案工作。你相信Raphael + AG會更好嗎? – 2013-04-10 10:24:47

+0

我的解決方案僅適用於svg路徑,因此您需要先將其他形狀轉換爲路徑(請參閱:https://github.com/johan/svg-js-utils/blob/master/paths.js,pathify() -功能)。我認爲轉換質量非常好(因爲您可以使用我建議的解決方案使用角度閾值和總體縮放參數來調整精度)。而且我也測試了Phrogz的解決方案,這是典型的強力方法,當形狀複雜且容易產生太多或太少的點時,解決方案很慢。 Antigrain解決方案產生最佳點數。什麼是AG? – 2013-04-10 15:26:22

+0

如果我看到足夠的代碼,我可以嘗試提供幫助。您可以使用[email protected]與我聯繫。也許更好的是,我們通過電子郵件繼續討論,找到解決方案後,在此發佈所需的步驟或功能。 – 2013-04-10 15:37:14