回答編集履歴

2

三次ベジェでの処理内容を正しいものに修正した。

2018/08/07 14:00

投稿

atata0319
atata0319

スコア881

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
- ![半径40](c1b6e3740b14cbf5108f58e295d70abe.png)
62
+
64
-
65
- ![半径240](a12486c67bf83e438cd71a7cb935635b.png)
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 = 'green';
281
+ ctx.strokeStyle = 'black';
254
-
255
- ctx.moveTo(xCA, yCA);
282
+
256
-
257
- ctx.quadraticCurveTo(0, 0, xCB, yCB);
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

画像が添付できていなかったのを足しました。

2018/08/07 14:00

投稿

atata0319
atata0319

スコア881

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
+ なお、偉そうにいってますが、上記のコードでは三次ベジェが正しく描画されていないように思えます。私が作った数式は間違っている以外に考えられのですが、問題を見つけることがきませんした