hubungan kurva bezier dan elips?

Saya ingin menggambar oval di kanvas html5, dan saya menemukan metode yang bagus untuk itu di stackoverflow.tapi saya punya pertanyaan lain.

function drawEllipse(ctx, x, y, w, h) {
  var kappa = 0.5522848;
      ox = (w / 2) * kappa, // control point offset horizontal
      oy = (h / 2) * kappa, // control point offset vertical
      xe = x + w,           // x-end
      ye = y + h,           // y-end
      xm = x + w / 2,       // x-middle
      ym = y + h / 2;       // y-middle

  ctx.beginPath();
  ctx.moveTo(x, ym);
  ctx.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);
  ctx.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);
  ctx.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);
  ctx.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);
  ctx.closePath();
  ctx.stroke();
}

metode pada tautan di atas telah menggunakan bezierCurveTo untuk menggambar elips, namun telah menggambar bezierCurveTo 4 kali. tapi menurut saya hanya 2 bezierCurveTo yang bisa menggambar elips. seperti ini:

masukkan deskripsi gambar di sini

tapi saya lemah dalam Matematika, bisakah seseorang memberi tahu saya hubungan "titik kontrol" dan "titik oval"? atau kita harus menggambar empat bezier Curve untuk menggambar oval?

terimakasih semuanya


person LIXer    schedule 05.01.2013    source sumber


Jawaban (5)


Latar belakang saya bukan matematika jadi jika saya salah saya yakin seseorang akan mengoreksi saya, tetapi dari pemahaman saya kita dapat menggambar perkiraan elips yang cukup bagus hanya dengan dua kurva bezier kubik < kuat>tapi koordinatnya akan sedikit rumit.

Untuk menjawab pertanyaan Anda tentang hubungan antara titik oval dan titik kontrol menurut saya sebaiknya dijawab dengan menonton video ini dari sudut pandang yang saya pilih jika Anda familiar dengan interpolasi atau dari awal jika Anda tidak. Jangan khawatir, ini pendek.

Satu masalah yang mungkin akan kita temui adalah ketika kita memulai dari atas dan melakukan bezierCurveTo bagian bawah elips dengan sudut persegi panjang (dengan lebar dan tinggi yang sama) sebagai titik kontrol, lebar elipsnya adalah akan lebih kecil dari persegi panjang. ,75 kali ukuran yang kita inginkan. Jadi kita tinggal menskalakan titik kontrolnya sesuai kebutuhan.

X titik kontrol kita akan disesuaikan seperti itu (dengan asumsi lebar adalah lebar elips dan kita membaginya dengan dua untuk mendapatkan offsetnya dari titik asal)

var cpx = (width / .75) / 2;

Buat visualisasi di mana Anda bisa bermain dengan lebar dan tinggi serta melihat gambarnya elips.

Elips merah adalah yang kita inginkan, dengan elips bagian dalam yang akan digambar jika kita tidak mengubah posisi titik kontrol. Garis tersebut menggambarkan algoritma De Casteljau yang ditampilkan dalam video.

Berikut screenshot visualisasinya masukkan deskripsi gambar di sini

person DerekR    schedule 05.01.2013

Anda hanya memerlukan dua kurva bezier kubik untuk menggambar elips. Berikut adalah versi sederhana dari kode DerekR yang menggunakan argumen fungsi asli yang Anda berikan--dengan asumsi Anda ingin x dan y menjadi pusat elips:

jsFiddle

function drawEllipse(ctx, x, y, w, h) {
    var width_over_2 = w / 2;
    var width_two_thirds = w * 2 / 3;
    var height_over_2 = h / 2;

    ctx.beginPath();
    ctx.moveTo(x, y - height_over_2);
    ctx.bezierCurveTo(x + width_two_thirds, y - height_over_2, x + width_two_thirds, y + height_over_2, x, y + height_over_2);
    ctx.bezierCurveTo(x - width_two_thirds, y + height_over_2, x - width_two_thirds, y - height_over_2, x, y -height_over_2);
    ctx.closePath();
    ctx.stroke();
}
person BKH    schedule 14.12.2013

Terima kasih sebesar-besarnya kepada BKH. Saya menggunakan kodenya dengan dua kurva bezier untuk menyelesaikan gambar elips saya dengan sudut rotasi apa pun. Juga, saya membuat demo perbandingan antara elips yang digambar oleh kurva bezier dan fungsi ellipse() asli (untuk saat ini hanya diterapkan di Chrome).

function drawEllipseByBezierCurves(ctx, x, y, radiusX, radiusY, rotationAngle) {
var width_two_thirds = radiusX * 4 / 3;

var dx1 = Math.sin(rotationAngle) * radiusY;
var dy1 = Math.cos(rotationAngle) * radiusY;
var dx2 = Math.cos(rotationAngle) * width_two_thirds;
var dy2 = Math.sin(rotationAngle) * width_two_thirds;

var topCenterX = x - dx1;
var topCenterY = y + dy1;
var topRightX = topCenterX + dx2;
var topRightY = topCenterY + dy2;
var topLeftX = topCenterX - dx2;
var topLeftY = topCenterY - dy2;

var bottomCenterX = x + dx1;
var bottomCenterY = y - dy1;
var bottomRightX = bottomCenterX + dx2;
var bottomRightY = bottomCenterY + dy2;
var bottomLeftX = bottomCenterX - dx2;
var bottomLeftY = bottomCenterY - dy2;

ctx.beginPath();
ctx.moveTo(bottomCenterX, bottomCenterY);
ctx.bezierCurveTo(bottomRightX, bottomRightY, topRightX, topRightY, topCenterX, topCenterY);
ctx.bezierCurveTo(topLeftX, topLeftY, bottomLeftX, bottomLeftY, bottomCenterX, bottomCenterY);
ctx.closePath();
ctx.stroke();

}

person PokatilovArt    schedule 26.02.2014

Anda akan menemukan penjelasan ini sedikit lebih berbasis matematika di http://pomax.github.io/bezierinfo/#circles_cubic, namun intinya adalah menggunakan kurva bezier kubik lebih dari seperempat putaran biasanya bukan ide yang baik. Untungnya, menggunakan empat kurva membuat pencarian titik kontrol yang diperlukan menjadi lebih mudah. Mulailah dengan sebuah lingkaran, dalam hal ini setiap seperempat lingkaran adalah (1,0)--(1,0.55228)--(0.55228,1)--(0,1) dengan koordinat skala untuk elips Anda. Gambarlah empat kali dengan tanda +/- yang ditukar untuk menghasilkan lingkaran penuh, skalakan dimensinya untuk mendapatkan elips, dan selesai.

Jika Anda menggunakan dua kurva, koordinatnya menjadi (1,0)--(1,4/3)--(-1,4/3)--(-1,0), diskalakan untuk elips Anda. Ini mungkin masih terlihat cukup layak di aplikasi Anda, itu tergantung pada seberapa besar gambar Anda nantinya.

person Mike 'Pomax' Kamermans    schedule 19.04.2013
comment
Sumber daya yang luar biasa! Dan memang Anda tidak bisa menggunakan 2 kurva Bezier untuk menggambar elips. Apakah perhitungannya dan untuk turunan kedua persamaannya tidak berakhir dengan baik. - person Alex; 28.02.2014

Dapat dibuktikan secara matematis, bahwa lingkaran tidak dapat dibuat dengan kurva Bézier berapapun derajatnya. Anda dapat membuat "hampir lingkaran" dengan memperkirakannya.

Katakanlah Anda ingin menggambar seperempat lingkaran di sekitar [0,0]. Koordinat kubik bézier adalah:

[0   , 1   ]
[0.55, 1   ]
[1   , 0.55]
[1   , 0   ]

Ini adalah perkiraan yang sangat bagus. Ubah secara linear untuk mendapatkan elpise.

person Ivan Kuckir    schedule 07.11.2013