2016-05-06 213 views
1

我試圖繪製多個並行路徑基於一組像這個例子中的座標的多個並行路徑:Paper.js借鑑一條路徑

enter image description here

我都基於一套創建我的路段,那麼我會克隆五次,並翻譯是這樣的:

var myPath; 
var lineData = []; // Long array of segments 
myPath.segments = lineData; 

for (var i = 1; i < 5; i++) { 
    var clone = myPath.clone(); 
    clone.translate(new paper.Point(0, i*5)); 
} 

這裏是結果我得到:

enter image description here

我想讓線條完全平行,但距離總是不一樣,它們有時會重疊。有沒有辦法解決它或mayby我應該嘗試不同的方法來創建這種曲線?

+0

沒那麼容易,因爲它看起來像一個貝塞爾曲線。您可以創建一組新的線段,並通過i * 5 * path.tangent偏移它們,如果紙張提供了這樣的功能(希望如此)或者它們可能具有某種偏移功能。另一種方法是通過用粗線繪製路徑來創建蒙版,繪製分段,再次用更細的路徑蒙版,然後再次分段,直到完成。因爲我不使用Paper.js,所以我可以僅使用2D API顯示切線方法,但這將很難翻譯回紙的路徑 – Blindman67

+0

三次貝塞爾曲線不能擴展爲另一個並行三次貝塞爾曲線。 @ Blindman67的沿着原始曲線計算切線的方法和這些切線上的繪製點將起作用。要開始,請參閱此問題[Q&A](http://stackoverflow.com/questions/24027087/gradient-stroke-along-curve-in-canvas/24029653#24029653),其中顯示了計算Bezier切點的算法曲線。您需要使用Q&A算法進行過採樣,並取消所得到的點集,直到沿曲線具有均勻距離處的切線。我喜歡你創建的可變寬度線。 :-) – markE

+0

可直接在PaperJS中工作的解決方案是通過將三次Bezier簡化爲一組近似二次貝塞爾曲線來逼近三次Bezier,然後使用PaperJS樣式來「點化」二次曲線。問題在於沿着你的二次近似的點(可能)不會與原始的立方貝塞爾相切。如果未對齊的點對於您的設計不是問題,請查看[本文](http://www.caffeineowl.com/graphics/2d/vectorial/cubic2quad01.html)。 – markE

回答

5

三次貝塞爾曲線不能擴展到另一個平行三次貝塞爾曲線。

@ Blindman67沿着原始曲線計算法線(正切線的垂線)的方法&在這些垂線上畫點會奏效。

要開始,請參閱此SO Q&A,其中顯示了計算垂直於貝塞爾曲線的點的算法。

下面是一個例子證明的概念:

如果你只是想紮實地平行曲線,然後過採樣通過設置tCount更高(例如tCount=500)。這個概念驗證使用點來創建線條,但對於實線曲線,您可以使用一組線條點。

enter image description here

待辦事項,如果你想虛線:你需要的算法進行過採樣(也許使用tCount=500而不是60)和重複數據刪除技術所得到的點集,直到你點沿着曲線以相同的距離。然後你的點不會稀疏沿曲線聚集。

enter image description here

var canvas=document.getElementById("canvas"); 
 
var ctx=canvas.getContext("2d"); 
 
var cw=canvas.width; 
 
var ch=canvas.height; 
 

 
// variables defining a cubic bezier curve 
 
var PI2=Math.PI*2; 
 
var s={x:20,y:30}; 
 
var c1={x:200,y:40}; 
 
var c2={x:40,y:200}; 
 
var e={x:270,y:220}; 
 

 
// an array of points plotted along the bezier curve 
 
var points=[]; 
 

 
// we use PI often so put it in a variable 
 
var PI=Math.PI; 
 

 
// plot 60 points along the curve 
 
// and also calculate the angle of the curve at that point 
 
var tCount=60; 
 
for(var t=0;t<=tCount;t++){ 
 

 
    var T=t/tCount; 
 

 
    // plot a point on the curve 
 
    var pos=getCubicBezierXYatT(s,c1,c2,e,T); 
 

 
    // calculate the perpendicular angle of the curve at that point 
 
    var tx = bezierTangent(s.x,c1.x,c2.x,e.x,T); 
 
    var ty = bezierTangent(s.y,c1.y,c2.y,e.y,T); 
 
    var a = Math.atan2(ty, tx)-PI/2; 
 

 
    // save the x/y position of the point and the perpendicular angle 
 
    // in the points array 
 
    points.push({ 
 
     x:pos.x, 
 
     y:pos.y, 
 
     angle:a 
 
    }); 
 
} 
 

 
var PI2=Math.PI*2; 
 
var radii=[-12,-6,0,6,12]; 
 

 
// fill the background 
 
ctx.fillStyle='navy'; 
 
ctx.fillRect(0,0,cw,ch); 
 

 
// draw a dots perpendicular to each point on the curve 
 
ctx.beginPath(); 
 
for(var i=0;i<points.length;i++){ 
 
    for(var j=-2;j<3;j++){ 
 
     var r=radii[j+2]; 
 
     var x=points[i].x+r*Math.cos(points[i].angle); 
 
     var y=points[i].y+r*Math.sin(points[i].angle); 
 
     ctx.moveTo(x,y); 
 
     ctx.arc(x,y,1.5,0,PI2); 
 
    } 
 
} 
 
ctx.fillStyle='skyblue'; 
 
ctx.fill(); 
 

 

 
////////////////////////////////////////// 
 
// helper functions 
 
////////////////////////////////////////// 
 

 
// calculate one XY point along Cubic Bezier at interval T 
 
// (where T==0.00 at the start of the curve and T==1.00 at the end) 
 
function getCubicBezierXYatT(startPt,controlPt1,controlPt2,endPt,T){ 
 
    var x=CubicN(T,startPt.x,controlPt1.x,controlPt2.x,endPt.x); 
 
    var y=CubicN(T,startPt.y,controlPt1.y,controlPt2.y,endPt.y); 
 
    return({x:x,y:y}); 
 
} 
 

 
// cubic helper formula at T distance 
 
function CubicN(T, a,b,c,d) { 
 
    var t2 = T * T; 
 
    var t3 = t2 * T; 
 
    return a + (-a * 3 + T * (3 * a - a * T)) * T 
 
    + (3 * b + T * (-6 * b + b * 3 * T)) * T 
 
    + (c * 3 - c * 3 * T) * t2 
 
    + d * t3; 
 
} 
 

 
// calculate the perpendicular angle at interval T on the curve 
 
function bezierTangent(a, b, c, d, t) { 
 
    return (3 * t * t * (-a + 3 * b - 3 * c + d) + 6 * t * (a - 2 * b + c) + 3 * (-a + b)); 
 
};
body{ background-color: ivory; } 
 
#canvas{border:1px solid red; margin:0 auto; }
<h4>Dotted parallel Bezier Curve.</h4> 
 
<canvas id="canvas" width=300 height=300></canvas>

+0

還有另一種方法可以創建一個平行Bezier的逼近(好的)。它通過抵消(沿正常方向)原始貝塞爾的部分來工作。因爲貝塞爾的小部分變得更像他們一樣。因此,您可以根據原始方向的變化率進行細分,在OP曲線上獲得3到4個分區的良好結果(在亞像素內)(順便說一句,我想說法線不切線*對不起*您應該更正答案)我只是在另一個問題上發佈貝塞爾分裂函數http://stackoverflow.com/a/37084481/3877726 – Blindman67

+1

@ Blindman67。是的,我在那裏看到了你很好的答案 - 但是在凌晨1點之後,所以我明天將不得不消化它。 :-)是的,正常是正確的描述(不正切 - 我的不好)。我將使用不太準確的術語「垂直」,因爲更多的觀衆可能會知道垂直與正常。乾杯! – markE

+0

markE,Blindman67你的回答非常有幫助謝謝! – Entaro