2013-08-30 35 views
0

我'使用KineticJS來繪製一個標誌,上下兩條線都是bezierCurveTo。在貝塞爾曲線內部得到一個點

我需要在它們之間畫線,所以我需要找到兩條曲線內的點。

我想用的是得到X座標並得到Y座標。 使用方法bezierCurveTo我可以找到位置。 問題是bezierCurve要使用第一個參數作爲百分比,而我的兩個berzier不等價,所以對我來說不是一個解決方案。

是否有任何給定樹點的函數並且X返回Y?

被修改

我會盡力與下一個例子 enter image description here 我已C點我需要的點A和B其是由給定的垂直線的交點更好地解釋它點C和貝塞爾曲線,但貝塞爾不是函數。

+0

你的問題是混亂的 - 至少對我來說:)你能發表你想要做什麼的形象嗎?或者也許重新提出你的問題。 – markE

+0

添加相關的代碼,因此很難理解你在說什麼。 – Ani

回答

2

給定一個X座標:如何獲得2個垂直堆疊貝塞爾曲線的Y座標。

我能想到2種方式,都使用「蠻力」。

第一種方法:檢查像素:

  • 畫上一個單獨的畫布上的兩個貝濟耶。
  • 使用context.getImageData獲得通過時,在您需要的X每個垂直的Y像素座標
  • 如果你找到一個非透明像素,您協調X.
  • 迭代在畫布上所有的垂直像素陣列「VE打貝塞爾(和它的Y)
  • 迭代從上到下,直到你找到頂級的貝塞爾Y.從底部
  • 迭代頂部,直到找到底部貝塞爾Y.

enter image description here

下面是第一方法代碼和小提琴:http://jsfiddle.net/m1erickson/uRDYf/

<!doctype html> 
<html> 
<head> 
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css --> 
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script> 

<style> 
    body{ background-color: ivory; } 
    #canvas{border:1px solid red;} 
</style> 

<script> 
$(function(){ 

    var canvas=document.getElementById("canvas"); 
    var ctx=canvas.getContext("2d"); 

    // draw a top bezier 
    ctx.beginPath(); 
    ctx.moveTo(50,50); 
    ctx.bezierCurveTo(125,0,150,100,250,75); 
    ctx.lineWidth=3; 
    ctx.strokeStyle="black"; 
    ctx.stroke(); 

    // draw a bottom bezier 
    ctx.beginPath(); 
    ctx.moveTo(50,150); 
    ctx.bezierCurveTo(125,0,150,100,250,175); 
    ctx.lineWidth=3; 
    ctx.strokeStyle="blue"; 
    ctx.stroke(); 

    // get an array of all the pixels in the canvas 
    var x=100; // put your X coordinate value here 
    var iData = ctx.getImageData(x,0,1,canvas.height); 
    var data = iData.data; 
    var w=canvas.width; 
    var h=canvas.height; 
    var theY1=-999; // your top result 
    var theY2=-999; // your bottom result 


    // iterate through each Y at your vertical X coordinate 
    // Examine the opacity value at the XY 
    // if the pixel is not transparent, you have found your Y 
    for(var y=0; y<h; y++) { 
     if(data[y*4+3]>10){ 
      theY1=y; 
      break; 
     } 
    } 

    // now iterate backwards to get the Y of the bottom curve 
    for(var y=0; y<h; y++) { 
     if(data[(h-y)*4+3]>10){ 
      theY2=(h-y); 
      break; 
     } 
    } 


    // testing -- display the results 

    ctx.beginPath(); 
    ctx.moveTo(x,0); 
    ctx.lineTo(x,h); 
    ctx.strokeStyle="lightgray"; 
    ctx.stroke(); 

    ctx.beginPath(); 
    ctx.arc(x,theY1,4,Math.PI*2,false); 
    ctx.closePath(); 
    ctx.arc(x,theY2,4,Math.PI*2,false); 
    ctx.closePath(); 
    ctx.fillStyle="red"; 
    ctx.fill(); 

}); // end $(function(){}); 
</script> 

</head> 

<body> 
    <canvas id="canvas" width=300 height=300></canvas> 
</body> 
</html> 

第二種方法:使用貝塞爾曲線式重複「猜測」的Y座標。

僅供參考,三次Bezier實際上確實有一個公式

// where ABCD are the control points and T is an interval along that curve 

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; 
} 

你可以沿着這個公式是這樣計算XY點:

// cubic bezier T is 0-1 
// When T==0.00, you are at the beginning of the Curve 
// When T==1.00, you are at the ending of the Curve 
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}); 
} 

所以第二個方法是重複「猜測「使用getCubicBezierXYatT沿曲線的T值。

當返回的X是你想要的X時,你也有你想要的Y.

我還沒有嘗試過,但這種SO後使用一種叫做牛頓迭代改進,以使其比隨機猜測更好:

Getting y from x co-ord for cubic bezier curve, fast Newton-Raphson method

+0

感謝您的回答,我結束了與您所說的類似的方法(我的優勢是我知道貝塞爾曲線可能的刻板印象)。非常好的牛頓 - 拉夫森方法,我會牢記在心 – aivaldi