2011-12-08 18 views
5

キャンバスにランダムな曲線の塊を描きたいのですが、私はそれを行うためのアルゴリズムを考え出すことができません。これで問題が頭にそれを取得している (これは単純化である...私はキャンバスの中などに行を制約するビットを追加しました)キャンバスの「ランダムな」曲線の形状

context.beginPath(); 
// Each shape should be made up of between three and six curves 
var i = random(3, 6); 
var startPos = { 
    x : random(0, canvas.width), 
    y : random(0, canvas.height) 
}; 
context.moveTo(startPos.x, startPos.y); 
while (i--) { 
    angle = random(0, 360); 
    // each line shouldn't be too long 
    length = random(0, canvas.width/5); 
    endPos = getLineEndPoint(startPos, length, angle); 
    bezier1Angle = random(angle - 90, angle + 90) % 360; 
    bezier2Angle = (180 + random(angle - 90, angle + 90)) % 360; 
    bezier1Length = random(0, length/2); 
    bezier2Length = random(0, length/2); 
    bezier1Pos = getLineEndPoint(startPos, bezier1Length, bezier1Angle); 
    bezier2Pos = getLineEndPoint(endPos, bezier2Length, bezier2Angle); 
    context.bezierCurveTo(
     bezier1Pos.x, bezier1Pos.y 
     bezier2Pos.x, bezier2Pos.y 
     endPos.x, endPos.y 
    ); 
    startPos = endPos; 
} 

:私はこのようなランダムなベジェ曲線を作成しようとしました出発点に戻って、厄介なコーナーの負荷をかけるだけではありません。誰もがこれを行うためのより良いアルゴリズムを知っている、または1つを考えることができますか?

編集:私はいくつかの進歩を遂げました。私はもう一度やり直しました。直線で作業しています(私はこのビットを使い果たしたら、スムースベジエにするために何をすべきか知っています)。私は各点を描く前に、前の点から始点までの距離と角度を計算するように設定しました。距離が一定量未満の場合は、曲線を閉じます。そうでなければ、可能な角度は反復回数に基づいて狭くなり、最大線長さは開始までの距離になります。だからここにいくつかのコードがあります。

start = { 
    // start somewhere within the canvas element 
    x: random(canvas.width), 
    y: random(canvas.height) 
}; 
context.moveTo(start.x, start.y); 
prev = {}; 
prev.length = random(minLineLength, maxLineLength); 
prev.angle = random(360); 
prev.x = start.x + prev.length * Math.cos(prev.angle); 
prev.y = start.y + prev.length * Math.sin(prev.angle); 

j = 1; 

keepGoing = true; 
while (keepGoing) { 
    j++; 
    distanceBackToStart = Math.round(
     Math.sqrt(Math.pow(prev.x - start.x, 2) + Math.pow(prev.y - start.y, 2))); 
    angleBackToStart = (Math.atan((prev.y - start.y)/(prev.x - start.x)) * 180/Math.pi) % 360; 
    if (isNaN(angleBackToStart)) { 
     angleBackToStart = random(360); 
    } 
    current = {}; 
    if (distanceBackToStart > minLineLength) { 
     current.length = random(minLineLength, distanceBackToStart); 
     current.angle = random(angleBackToStart - 90/j, angleBackToStart + 90/j) % 360; 
     current.x = prev.x + current.length * Math.cos(current.angle); 
     current.y = prev.y + current.length * Math.sin(current.angle); 
     prev = current; 
    } else { 
     // if there's only a short distance back to the start, join up the curve 
     current.length = distanceBackToStart; 
     current.angle = angleBackToStart; 
     current.x = start.x; 
     current.y = start.y; 
     keepGoing = false; 
    } 
    context.lineTo(current.x, current.y); 
} 
console.log('Shape complexity: ' + j); 
context.closePath(); 
context.fillStyle = 'black'; 
context.shadowColor = 'black'; 
context.shadowOffsetX = -xOffset; 
context.shadowOffsetY = -yOffset; 
context.shadowBlur = 50; 
context.fill(); 

私が今持っている問題は、形状の輪郭がしばしば交差して見えてしまうことです。これは間違っています。私がこれを解決するために考えることができる唯一の方法は、バウンディングボックスを追跡することです。そして、それぞれの新しいポイントは、常に境界ボックスの外に出てください。利用可能な角度を計算することは、全体的な複雑さを増すので、難しいです。

+0

JavaScriptインラインでHTMLページ全体を投稿する必要があります。 – Fantius

+1

http://stackoverflow.com/questions/2956967/drawing-path-by-bezier-curves – Fantius

+0

コードはjsfiddleです:http://jsfiddle.net/EnZX4/ –

答えて

3

1つの可能性は、極座標を使用し、半径を角度の関数とすることです。係数が「ランダム」です

radius(theta) = a_0 + a_1*sin(theta) + a_2*sin(2*theta) + ... + b_1*cos(theta) + ... 

:なめらかな塊のためには、半径が滑らかで、そして三角多項式を使用して行うことができ、0と2 * piの、で同じ値を持っていると思います。半径の大きさと大きさを制御するには、半径関数の最大値と最小値を検索し、係数を適切にシフトしてスケールすることができます(つまり、rlo < = r < = rhiとし、 b =(rhi-rlo)/(max-min)とa = rlo-b * minの各係数a + b * originalを置き換えます。

+0

それはすばらしいアイデアです!私は何か働くことができるかどうかを見て回ります。 –