2011-12-08 33 views
5

Tôi muốn vẽ các đốm màu cong trông ngẫu nhiên trên canvas, nhưng dường như tôi không thể tìm ra thuật toán để làm điều đó. Tôi đã cố gắng tạo ra các đường cong Bezier ngẫu nhiên như thế này:canvas hình dạng cong "ngẫu nhiên"

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

(Đây là một việc đơn giản hóa ... Tôi thêm bit hạn chế các dòng để trong vải, vv) Vấn đề ở đây là nhận được nó để đầu trở lại điểm khởi đầu, và cũng không chỉ tạo ra vô số góc vụng về. Có ai biết về một thuật toán tốt hơn để làm điều này, hoặc có thể nghĩ ra một trong những?

Chỉnh sửa: Tôi đã thực hiện một số tiến bộ. Tôi đã bắt đầu một lần nữa, làm việc với các đường thẳng (tôi nghĩ tôi biết phải làm gì để biến chúng thành Beziers trơn tru một khi tôi đã làm việc này một chút). Tôi đã thiết lập nó sao cho trước khi vẽ từng điểm, nó làm việc ra khoảng cách và góc để bắt đầu từ điểm trước đó. Nếu khoảng cách nhỏ hơn một số tiền nhất định, nó sẽ đóng đường cong. Nếu không, góc có thể thu hẹp dựa trên số lần lặp lại và chiều dài dòng tối đa là khoảng cách đến điểm bắt đầu. Đây là một số mã.

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(); 

Vấn đề tôi có bây giờ là hình dạng của phác thảo thường đi qua chính nó, trông có vẻ sai. Cách duy nhất tôi có thể nghĩ đến để giải quyết vấn đề này là theo dõi một hộp giới hạn, và mỗi điểm mới phải luôn đi ra khỏi hộp giới hạn. Đó là khó khăn bởi vì tính toán góc sẵn có thêm một mức độ phức tạp toàn bộ.

+0

Bạn nên đăng toàn bộ trang HTML, với nội tuyến JavaScript. – Fantius

+1

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

+0

Đây là một jsfiddle với mã của mình: http://jsfiddle.net/EnZX4/ –

Trả lời

3

Một khả năng là sử dụng tọa độ cực và có bán kính là hàm của góc. Đối với các đốm màu trơn bạn muốn bán kính để được mịn màng, và có cùng giá trị 0 và 2 * pi, có thể được thực hiện bằng một đa thức lượng giác:

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

nơi các hệ số là "ngẫu nhiên". Để kiểm soát mức độ lớn nhất và nhỏ của bán kính, bạn có thể tìm kiếm giá trị cực đại và cực đại của hàm bán kính, sau đó thay đổi tỷ lệ hệ số thích hợp (ví dụ: nếu bạn muốn rlo < = r < = rhi, và đã tìm thấy min và max, sau đó thay thế từng hệ số a + b * gốc, trong đó b = (rhi-rlo)/(max-min) và a = rlo-b * min).

+0

Đó là một ý tưởng tuyệt vời! Tôi sẽ có một trò chơi xung quanh sau đó xem nếu tôi có thể nhận được một cái gì đó làm việc. –

Các vấn đề liên quan