2011-09-08 2 views
8

내 응용 프로그램 중 하나는 Html5 캔버스의 베 지어 패스에 점선으로 그려야합니다 ... 대시의 길이와 간격은 가변적이어야합니다 ... 이것은 achivable입니다. JavaFx, see this link ... 나는 Html5 캔버스를 사용하여 동일한 효과를 얻고 싶습니다. 나는 점선을 그리는 방법을 알고 있지만 베 지어를 따라 곡선을 그리지는 않습니다 ...Html5 캔버스 베 지어에 점선으로 된 커브

비록 내가 전문가가 아니지만 bezier drawing algorithm을 알고 있습니다.이 알고리즘으로 볼 수있는 문제는 다음과 같습니다. 0에서 1까지의 시간 매개 변수를 사용하는 베 지어 ...

파선 된 베 지어를 그리기 때문에 충분하지 않습니다. 지정된 길이 매개 변수와 주어진 간격 거리에서 많은 작은 베 지어를 그릴 필요가 있습니다. 주 베 지어 경로. JavaFx에서 사용하는 알고리즘이 있어야합니다. 누군가가 나를 도울 수 있다면 그것은 좋을 것입니다.

+0

여기에 점선 곡선에 적응 할 수있을 것으로 비슷한의 스마트 구현이 있습니다 : http://stackoverflow.com/questions/를 4576724/점선으로 된 스트로크 인 캔버스 예제 : http://phrogz.net/tmp/canvas_dashed_line.html – unmounted

+0

내가 말했듯이, 나는 파선을 그릴 방법을 안다. 문제는 파선을 파선으로 그리는 방법이다. 베 지어 경로 ... –

+0

bez 드로잉 알 고에서 mod op (%)를 사용할 수 있습니다. 짝수 위치의 경우 알파를 0으로 설정하고 곡선의 길이에 비례하여 홀수 위치의 경우 알파를 설정합니다. 베 지어 알 고를 나에게 제공 할 수 있다면이 수학을 연결해도 상관 없습니다. –

답변

4

나는 JavaFX가 점선 곡선을 그리기위한 일반적인 기술을 사용하고 있으며, 그 예에서 베 지어에서이 코드를 사용하고 있다고 가정합니다.

어려운 부분은 각 대시를 시작하고 중지 할 위치를 알아내는 것입니다.이 지점에서는 다양한 점에서 베지에 곡선의 arc length을 알아야합니다.

은 분석 방법이있다, 그러나 나는 다음을 제안 :이 방법

var bezier = function(controlPoints, t) { 
    /* your code here, I'll presume it returns a 2-element array of x and y. */ 
}; 

//just figure out the coordinates of all the points in each dash, don't draw. 
//returns an array of arrays, each sub-array will have an even number of nu- 
//merical elements, to wit, x and y pairs. 

//Argument dashPattern should be an array of alternating dash and space 
//lengths, e.g., [10, 10] would be dots, [30, 10] would be dashes, 
//[30, 10, 10, 10] would be 30-length dash, 10-length spaces, 10-length dash 
// and 10-length space. 
var calculateDashedBezier = function(controlPoints, dashPattern) { 
    var step = 0.001; //this really should be set by an intelligent method, 
        //rather than using a constant, but it serves as an 
        //example. 

    //possibly gratuitous helper functions 
    var delta = function(p0, p1) { 
    return [p1[0] - p0[0], p1[1] - p0[1]]; 
    }; 
    var arcLength = function(p0, p1) { 
    var d = delta(p0, p1); 
    return Math.sqrt(d[0]*d[0] + d[1] * d[1]); 
    }; 

    var subPaths = []; 
    var loc = bezier(controlPoints, 0); 
    var lastLoc = loc; 

    var dashIndex = 0; 
    var length = 0; 
    var thisPath = []; 
    for(var t = step; t <= 1; t += step) { 
    loc = bezier(controlPoints, t); 
    length += arcLength(lastLoc, loc); 
    lastLoc = loc; 

    //detect when we come to the end of a dash or space 
    if(length >= dashPattern[dashIndex]) { 

     //if we are on a dash, we need to record the path. 
     if(dashIndex % 2 == 0) 
     subPaths.push(thisPath); 

     //go to the next dash or space in the pattern 
     dashIndex = (dashIndex + 1) % dashPattern.length; 

     //clear the arclength and path. 
     thisPath = []; 
     length = 0; 
    } 

    //if we are on a dash and not a space, add a point to the path. 
    if(dashIndex % 2 == 0) { 
     thisPath.push(loc[0], loc[1]); 
    } 
    } 
    if(thisPath.length > 0) 
    subPaths.push(thisPath); 
    return subPaths; 
}; 

//take output of the previous function and build an appropriate path 
var pathParts = function(ctx, pathParts) { 
    for(var i = 0; i < pathParts.length; i++) { 
    var part = pathParts[i]; 
    if(part.length > 0) 
     ctx.moveTo(part[0], part[1]); 
    for(var j = 1; j < part.length/2; j++) { 
     ctx.lineTo(part[2*j], part[2*j+1]); 
    } 
    } 
}; 

//combine the above two functions to actually draw a dashed curve. 
var drawDashedBezier = function(ctx, controlPoints, dashPattern) { 
    var dashes = calculateDashedBezier(controlPoints, dashPattern); 
    ctx.beginPath(); 
    ctx.strokeStyle = /* ... */ 
    ctx.lineWidth = /* ... */ 
    pathParts(ctx, dashes); 
    ctx.stroke(); 
}; 

가장 큰 문제는 비지 단위입니다. 단계가 너의 (작은) 대시 또는 (큰) 커브를 위해 너무 클 때, 단계 크기는 잘 작동하지 않을 것이고 돌진 경계는 너가 원하는 곳에 정확하게 떨어지지 않을 것이다. step이 너무 작 으면, 서브 픽셀 간격으로 서로 떨어져있는 점에서 lineTo()을 끝내고 AA 인공물을 만드는 경우가 있습니다. 하위 픽셀 거리 좌표를 필터링하는 것은 어렵지 않지만 실제로 필요한 것보다 많은 '꼭짓점'을 생성하는 것은 비효율적입니다. 더 나은 단계 크기를 생각해내는 것은 사실 더 분석적으로 공격하는 것으로 간주됩니다.

이 접근법을 사용하면 보너스가 하나 있습니다 : bezier(controlPoints, t)을 커브로 평가하는 다른 것으로 바꾼다면 이전 단락에 나열된 것과 같은 잠재적 문제가있는 점선으로 된 위풍 당김을 다시 그릴 수 있습니다. 그러나 세분성 문제에 대한 정말 좋은 해결책은 모든 '잘 작동하는'곡선에서 작동 할 수 있습니다. 향후

+1

고급 단계에서 베 지어 크기를 알 수 없으므로 step = 0.001로 가정하는 것이 큰 위험입니다. 두 점의 거리가 0이되거나 곡선이 직선이 될 때까지 중간 점을 찾아 단계를 재귀 적으로 계산하면 더 좋을 것입니다 ... –

+0

또 다른 쉬운 방법은 호 길이의 근사치와 동일한 'step'을 설정하는 것입니다 베 지어 곡선의 가장 큰 대시 길이로 나눈 값입니다. 그럼에도 불구하고 커브가 '1/step'이 아크 길이를 가장 작은 대시 길이로 나눈 것보다 훨씬 큰 경우 '고정'단계가 잘 작동합니다. – ellisbben

+0

덕분에 도움이되었습니다 ... –