7

さまざまなストローク幅を持つ線、曲線、およびポリラインのマウスオーバーイベントを検出するメカニズムが必要です。長方形と楕円に対してそのようなメカニズムを既に作成しているため、キャンバス API は初めてではありません。描画されたすべてのオブジェクトの輪郭を描き、それらの上のマウスの位置を検出します。長方形または楕円のストローク幅が 1 ピクセルを超える場合は、境界線も含まれるようにパスを拡張します。線とポリラインの場合、たとえば lineWidth が 20 ピクセルの場合、それらをどのように拡張すればよいかを理解するのは困難です。

私の質問は、このパスがすべての幅を含むように、線、曲線、およびポリラインを形状パスで変換する方法ですか?

赤 - パス、黒 - ストローク パス

作成されたパスには、この画像で黒で表される線/曲線の幅が含まれている必要があります。

----------もう少し情報----------

問題を単純化してみましょう: 2 つの点 (下の画像では赤で表示) があり、それらは特定の式 (y = mx + n) を持つ線を形成します。次の垂線の式を決定する必要があります。これらの 2 つの初期ポイントを通過した後、context.lineWidth の値の半分の距離にある「青い」ポイントの位置を決定する必要があります。すべてのポイントが決定されると、 moveTo() および lineTo() シーケンスを使用した新しいパス。この方法は、制御点を使用する 2 次およびベジエ曲線に適用できます。問題は、これらの数学的計算にのみ残ります。

4

3 に答える 3

3

math.stackexchange hereで解決策を見つけました。この解決策は線のみですが、特定の変更を加えた曲線とポリラインに適用できます。まず、2 つのイニシャル ポイントを通る直線の式を決定する必要があります。

ステップ1

ポイント: P1(x1, y1) および P2(x2, y2)

ポイントとその隣接ポイント間の距離: d

一般形: Ax + By + C = 0

ここで: A = y2 - y1; B = x1 - x2; C = x2y1 - x1y2。

その後、この式を短い形式で定義する必要があります。

ステップ2

省略形: y = mx +n

ここで: m = - A / B; n = - C / B. (B != 0 の場合)

A == 0 の場合、次の式が得られます: y = C (水平線がある場合)

B == 0 の場合、次の式が得られます: x = C (垂直線がある場合)

線の傾きがある場合、それに垂直な線の傾きが必要です。

ステップ 3

垂線勾配: m2 = - 1 / m

A == 0 または B == 0 の場合は、手順 4 に進みます。

次に、両方の初期点の隣接点を取得する必要があります。

ステップ 4

最初のポイントは P1N1、P1N2、2 番目のポイントは P2N1 と P2N2 として隣接ポイントに注意します。

特殊なケース (水平線と垂直線、A == 0 または B == 0 の場合) では、次のようになります。

A == 0 (水平線) の場合:

P1N1(x1, y1 - d / 2); P1N2(x1, y1 + d / 2); P2N1(x2, y2 + d / 2); P2N2(x2, y2 - d / 2)。

B == 0 (垂直線) の場合:

P1N1(x1 - d / 2, y1); P1N2(x1 + d / 2, y1); P2N1(x2 + d / 2, y2); P2N2(x2 - d / 2, y2)。

その他の場合 (A != 0 および B != 0):

P1N1:

x = (d / 2) / Math.sqrt(1 + Math.pow(m2, 2)) + x1;

y = (m2 * (d / 2)) / Math.sqrt(1 + Math.pow(m2, 2)) + y1;

P1N2:

x = - (d / 2) / Math.sqrt(1 + Math.pow(m2, 2)) + x1;

y = - (m2 * (d / 2)) / Math.sqrt(1 + Math.pow(m2, 2)) + y1;

P2N1:

x = (d / 2) / Math.sqrt(1 + Math.pow(m2, 2)) + x2;

y = (m2 * (d / 2)) / Math.sqrt(1 + Math.pow(m2, 2)) + y2;

P2N2:

x = - (d / 2) / Math.sqrt(1 + Math.pow(m2, 2)) + x2;

y = - (m2 * (d / 2)) / Math.sqrt(1 + Math.pow(m2, 2)) + y2;

これらの数式をアプリケーションに実装する場合は、パフォーマンスを向上させるために結果をキャッシュする必要があります。

于 2012-07-18T06:26:53.683 に答える
2

ベジエ曲線が次の形式の場合。

x(t) = x0 + x1*t + x2*t*t + x3*t*t*t
y(t) = y0 + y1*t + y2*t*t + y3*t*t*t

次に、その導関数を計算する必要があります。これにより、任意の点で接線が得られます。

x'(t) = x1 + 2*x2*t + 3*x3*t*t
y'(t) = y1 + 2*y2*t + 3*y3*t*t

そして任意の点での法線。法線は、任意の点での垂線であり、2 点をサポートするものです。

(-y'(t), x'(t))
((y'(t), -(x'(t))
于 2012-07-16T23:19:14.850 に答える