回答編集履歴
2
三次ベジェでの処理内容を正しいものに修正した。
test
CHANGED
@@ -38,7 +38,7 @@
|
|
38
38
|
|
39
39
|
7.ベクトルAとベクトルBの単位ベクトルを掛け算して図上のCAとCBの座標を求める。
|
40
40
|
|
41
|
-
ここまでの手順で bezierCurveTo によって疑似円弧を描画する情報は集まっています。
|
41
|
+
~~ここまでの手順で bezierCurveTo によって疑似円弧を描画する情報は集まっています。~~
|
42
42
|
|
43
43
|
|
44
44
|
|
@@ -58,11 +58,11 @@
|
|
58
58
|
|
59
59
|
|
60
60
|
|
61
|
-
|
61
|
+
円弧を赤、二次ベジェ曲線を緑で描画しています。
|
62
|
-
|
63
|
-
|
62
|
+
|
64
|
-
|
65
|
-
![
|
63
|
+
![arcで描画](715fec3d880d12a368492244547ba12c.png)![bezierCurveToで描画](878d51dea17deebb340e156b2686450a.png)
|
64
|
+
|
65
|
+
|
66
66
|
|
67
67
|
コードにする以下のような感じです。
|
68
68
|
|
@@ -92,6 +92,8 @@
|
|
92
92
|
|
93
93
|
半径:<input id="input_r" value="40" /><br />
|
94
94
|
|
95
|
+
<input type="checkbox" id="arc" checked /><label for="arc">arc</label><input type="checkbox" id="bezierCurveTo" checked /><label for="bezierCurveTo">bezierCurveTo</label><input type="checkbox" id="quadraticCurveTo" /><label for="quadraticCurveTo">quadraticCurveTo</label><br />
|
96
|
+
|
95
97
|
<canvas id="canvas" width="500" height="500"></canvas>
|
96
98
|
|
97
99
|
</body>
|
@@ -122,8 +124,6 @@
|
|
122
124
|
|
123
125
|
const r = input_r.value;
|
124
126
|
|
125
|
-
const k = 4 * (Math.sqrt(2) - 1) / 3;
|
126
|
-
|
127
127
|
|
128
128
|
|
129
129
|
const ctx = canvas.getContext('2d');
|
@@ -248,68 +248,44 @@
|
|
248
248
|
|
249
249
|
// 制御点をPとした二次ベジェを描画してみる。
|
250
250
|
|
251
|
+
if (quadraticCurveTo.checked) {
|
252
|
+
|
253
|
+
ctx.beginPath();
|
254
|
+
|
255
|
+
ctx.strokeStyle = 'green';
|
256
|
+
|
257
|
+
ctx.moveTo(xCA, yCA);
|
258
|
+
|
259
|
+
ctx.quadraticCurveTo(0, 0, xCB, yCB);
|
260
|
+
|
261
|
+
ctx.stroke();
|
262
|
+
|
263
|
+
}
|
264
|
+
|
265
|
+
|
266
|
+
|
267
|
+
// 8.円の中心を求める。
|
268
|
+
|
269
|
+
// 円の中心ベクトルはベクトルMの単位ベクトルに対辺の長さを掛けたものになる。
|
270
|
+
|
271
|
+
const xE = xUM * r / sin;
|
272
|
+
|
273
|
+
const yE = yUM * r / sin;
|
274
|
+
|
275
|
+
|
276
|
+
|
277
|
+
// 参考のために円を描画する。
|
278
|
+
|
251
279
|
ctx.beginPath();
|
252
280
|
|
253
|
-
ctx.strokeStyle = '
|
281
|
+
ctx.strokeStyle = 'black';
|
254
|
-
|
255
|
-
|
282
|
+
|
256
|
-
|
257
|
-
ctx.
|
283
|
+
ctx.arc(xE, yE, r, 0, 2 * Math.PI);
|
258
284
|
|
259
285
|
ctx.stroke();
|
260
286
|
|
261
287
|
|
262
288
|
|
263
|
-
// 三次ベジェを描画してみる。
|
264
|
-
|
265
|
-
// https://cat-in-136.github.io/2014/03/bezier-1-kappa.html
|
266
|
-
|
267
|
-
ctx.beginPath();
|
268
|
-
|
269
|
-
ctx.strokeStyle = 'blue';
|
270
|
-
|
271
|
-
ctx.moveTo(xCA, yCA);
|
272
|
-
|
273
|
-
ctx.bezierCurveTo(
|
274
|
-
|
275
|
-
xCA - xUA * r * k,
|
276
|
-
|
277
|
-
yCA - yUA * r * k,
|
278
|
-
|
279
|
-
xCB - xUB * r * k,
|
280
|
-
|
281
|
-
yCB - yUB * r * k,
|
282
|
-
|
283
|
-
xCB,
|
284
|
-
|
285
|
-
yCB);
|
286
|
-
|
287
|
-
ctx.stroke();
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
// 8.円の中心を求める。
|
292
|
-
|
293
|
-
// 円の中心ベクトルはベクトルMの単位ベクトルに対辺の長さを掛けたものになる。
|
294
|
-
|
295
|
-
const xE = xUM * r / sin;
|
296
|
-
|
297
|
-
const yE = yUM * r / sin;
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
// 参考のために円を描画する。
|
302
|
-
|
303
|
-
ctx.beginPath();
|
304
|
-
|
305
|
-
ctx.strokeStyle = 'black';
|
306
|
-
|
307
|
-
ctx.arc(xE, yE, r, 0, 2 * Math.PI);
|
308
|
-
|
309
|
-
ctx.stroke();
|
310
|
-
|
311
|
-
|
312
|
-
|
313
289
|
// 9.A接点の角度を求める。
|
314
290
|
|
315
291
|
const thetaCA = Math.atan2(yCA - yE, xCA - xE);
|
@@ -322,15 +298,77 @@
|
|
322
298
|
|
323
299
|
|
324
300
|
|
301
|
+
// 10.三次ベジェを描画してみる。
|
302
|
+
|
303
|
+
if (bezierCurveTo.checked) {
|
304
|
+
|
305
|
+
// κ値を計算する。
|
306
|
+
|
307
|
+
// https://cat-in-136.github.io/2014/03/bezier-3-general-theta.html
|
308
|
+
|
309
|
+
const k = 4 * Math.tan(Math.abs(thetaCA - thetaCB) / 4) / 3;
|
310
|
+
|
311
|
+
|
312
|
+
|
313
|
+
// A側制御点
|
314
|
+
|
315
|
+
const xCPA = xCA - xUA * r * k;
|
316
|
+
|
317
|
+
const yCPA = yCA - yUA * r * k;
|
318
|
+
|
319
|
+
ctx.beginPath();
|
320
|
+
|
321
|
+
ctx.fillStyle = 'blue';
|
322
|
+
|
323
|
+
ctx.arc(xCPA, yCPA, 2, 0, 2 * Math.PI);
|
324
|
+
|
325
|
+
ctx.fill();
|
326
|
+
|
327
|
+
|
328
|
+
|
329
|
+
// B側制御点
|
330
|
+
|
331
|
+
const xCPB = xCB - xUB * r * k;
|
332
|
+
|
333
|
+
const yCPB = yCB - yUB * r * k;
|
334
|
+
|
335
|
+
ctx.beginPath();
|
336
|
+
|
337
|
+
ctx.fillStyle = 'blue';
|
338
|
+
|
339
|
+
ctx.arc(xCPB, yCPB, 2, 0, 2 * Math.PI);
|
340
|
+
|
341
|
+
ctx.fill();
|
342
|
+
|
343
|
+
|
344
|
+
|
345
|
+
ctx.beginPath();
|
346
|
+
|
347
|
+
ctx.strokeStyle = 'blue';
|
348
|
+
|
349
|
+
ctx.moveTo(xCA, yCA);
|
350
|
+
|
351
|
+
ctx.bezierCurveTo(xCPA, yCPA, xCPB, yCPB, xCB, yCB);
|
352
|
+
|
353
|
+
ctx.stroke();
|
354
|
+
|
355
|
+
}
|
356
|
+
|
357
|
+
|
358
|
+
|
325
359
|
// 10.円弧を描画する。
|
326
360
|
|
361
|
+
if (arc.checked) {
|
362
|
+
|
327
|
-
ctx.beginPath();
|
363
|
+
ctx.beginPath();
|
328
|
-
|
364
|
+
|
329
|
-
ctx.strokeStyle = 'red';
|
365
|
+
ctx.strokeStyle = 'red';
|
330
|
-
|
366
|
+
|
331
|
-
ctx.arc(xE, yE, r, Math.min(thetaCA, thetaCB), Math.max(thetaCA, thetaCB));
|
367
|
+
ctx.arc(xE, yE, r, Math.min(thetaCA, thetaCB), Math.max(thetaCA, thetaCB));
|
332
|
-
|
368
|
+
|
333
|
-
ctx.stroke();
|
369
|
+
ctx.stroke();
|
370
|
+
|
371
|
+
}
|
334
372
|
|
335
373
|
|
336
374
|
|
@@ -354,6 +392,12 @@
|
|
354
392
|
|
355
393
|
input_r.addEventListener('input', onInput, false);
|
356
394
|
|
395
|
+
arc.addEventListener('change', onInput, false);
|
396
|
+
|
397
|
+
bezierCurveTo.addEventListener('change', onInput, false);
|
398
|
+
|
399
|
+
quadraticCurveTo.addEventListener('change', onInput, false);
|
400
|
+
|
357
401
|
|
358
402
|
|
359
403
|
onInput();
|
@@ -377,3 +421,13 @@
|
|
377
421
|
|
378
422
|
|
379
423
|
なお、偉そうにいってますが、上記のコードでは三次ベジェが正しく描画されていないように思えます。私が作った数式は間違っている以外に考えられないのですが、問題を見つけることができませんでした。
|
424
|
+
|
425
|
+
|
426
|
+
|
427
|
+
---
|
428
|
+
|
429
|
+
問題点が分かりました。最初のプログラムではκ値を固定値としていましたが、2つの線分の角度によってκ値を計算する必要があったようです。
|
430
|
+
|
431
|
+
[https://cat-in-136.github.io/2014/03/bezier-3-general-theta.html](https://cat-in-136.github.io/2014/03/bezier-3-general-theta.html)
|
432
|
+
|
433
|
+
文中のコードも修正してあります。結果として2点の角度を求める必要があるため、arc で処理するのも bezierCurveTo も計算量は同じになりました。cosθから計算することもできますが、数式を考えるのが面倒なのでやってません。
|
1
画像が添付できていなかったのを足しました。
test
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
|
5
5
|
|
6
6
|
|
7
|
-
|
7
|
+
![記号の説明](cc1cda1c1eec6f56d172fe7fbfa7bc34.png)
|
8
8
|
|
9
9
|
|
10
10
|
|
@@ -58,7 +58,13 @@
|
|
58
58
|
|
59
59
|
|
60
60
|
|
61
|
-
|
61
|
+
新円を赤、二次ベジェ曲線を緑、三次ベジェ曲線を青で描画しています。
|
62
|
+
|
63
|
+
![半径40](c1b6e3740b14cbf5108f58e295d70abe.png)
|
64
|
+
|
65
|
+
![半径240](a12486c67bf83e438cd71a7cb935635b.png)
|
66
|
+
|
67
|
+
コードにする以下のような感じです。
|
62
68
|
|
63
69
|
```HTML
|
64
70
|
|
@@ -362,10 +368,12 @@
|
|
362
368
|
|
363
369
|
```
|
364
370
|
|
371
|
+
Chrome と Edge で確認しています。
|
372
|
+
|
365
373
|
単一のHTMLですが github にも上げてみました。
|
366
374
|
|
367
375
|
[https://github.com/atata0319/teratail139697](https://github.com/atata0319/teratail139697)
|
368
376
|
|
369
377
|
|
370
378
|
|
371
|
-
偉そうにいってますが、上記のコードでは三次ベジェが正しく描画されていないように思えます。数式は間違ってな
|
379
|
+
なお、偉そうにいってますが、上記のコードでは三次ベジェが正しく描画されていないように思えます。私が作った数式は間違っている以外に考えられないのですが、問題を見つけることができませんでした。
|