私は、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();
};
主な問題は、その非インテリジェントな粒度です。ステップがあなたの(小さい)ダッシュや(大きな)カーブには大きすぎると、ステップサイズがうまく機能せず、ダッシュ境界があなたが望む場所に正確には収まらなくなります。ステップが小さすぎると、サブピクセルの距離が離れている点でlineTo()
秒を過ぎることがあり、時にはAAアーティファクトが発生します。サブピクセルの距離座標をフィルタリングすることは困難ではありませんが、実際に必要とするより多くの「頂点」を生成することは非効率的です。より良いステップサイズが登場するのは、実際には私はより分析的に攻撃すると考えています。
bezier(controlPoints, t)
をカーブに評価するものに置き換えた場合、前の段落にリストされている同様の潜在的な問題があります。しかし粒状性の問題に対する本当に良い解決策は、すべての「よく振舞われた」曲線でうまくいく可能性があります。将来的には
あなたがここに点線の曲線に適応することができるかもしれという似たようなのスマートな実装があります:http://stackoverflow.com/questions/を4576724/dotted-stroke-in-canvasここでのライブ例:http://phrogz.net/tmp/canvas_dashed_line.html – unmounted
私が言ったように、私は破線をプロットする方法を知っていますが、問題は点線の曲線をベジェパス... –
私はbez描画アルゴでmod op(%)を使うことができると思います。偶数位置の場合はアルファをゼロに設定し、長さを基準にしてカーブの奇数位置の場合はアルファを通常に設定します。あなたが私にベジエ・アルゴを与えることができれば、私はこの数学を差し込んでも構いません。:) –