2011-12-08 2 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; 
} 

(이것은 ... 단순화이다 I 등 캔버스 내로 라인 구속 비트를 첨가) 이 가진 문제는 머리를 받고 출발점으로 돌아가고, 어색한 모서리를 짓는 것 뿐만이 아닙니다. 누구든지이 작업을 수행하는 데 더 좋은 알고리즘을 알고 있습니까? 아니면 하나를 생각할 수 있습니까?

편집 : 나는 약간의 진전을 보였습니다. 나는 직선으로 작업을 다시 시작했다. (일단이 비트를 풀어 냈다면 부드럽게 베 지어로 만들기 위해 무엇을해야하는지 알 것 같다.) 각 점을 그리기 전에 이전 점으로부터 시작점까지의 거리와 각도를 계산하도록 설정했습니다. 거리가 특정 양보다 작 으면 곡선을 닫습니다. 그렇지 않으면 가능한 각도가 반복 횟수를 기준으로 좁혀지고 최대 줄 길이는 시작까지의 거리입니다. 여기에 몇 가지 코드가 있습니다.

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

자바 스크립트 인라인으로 전체 HTML 페이지를 게시해야합니다. – Fantius

+1

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

+0

다음은 코드와 함께 jsfiddle입니다. http://jsfiddle.net/EnZX4/ –

답변

3

극좌표를 사용하고 반경을 각도의 함수로 지정할 수도 있습니다.

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

계수가 "임의"입니다 : 부드러운 모양을 위해 당신은 반경이 부드러운되고 싶어하고, 삼각 다항식을 사용하여 수행 할 수 있습니다 0, 2 * 파이에서 같은 값을 가지고있다. 반지름의 크고 작은 크기를 제어하려면 반경 함수의 최대 값과 최소값을 검색 한 다음 계수를 적절하게 이동하고 크기를 조정할 수 있습니다 (예 : rlo < = r < = rhi를 원하고 min과 max를 찾았 으면) b = (rhi-rlo)/(max-min) 및 a = rlo-b * min 인 각 계수 a + b * original을 대체하십시오.

+0

놀라운 아이디어입니다! 나는 주변에서 놀 수있는 뭔가를 얻을 수 있는지. –