Làm thế nào để tạo đường tròn với đường cong Bézier?


99

Chúng ta có điểm đầu (x, y) và bán kính đường tròn. Cũng có một công cụ có thể tạo ra một đường đi từ các điểm của đường cong Bézier.

Làm thế nào tôi có thể tạo một vòng tròn bằng cách sử dụng các đường cong Bézier?


Câu trả lời:


138

Như đã nói: không có biểu diễn chính xác của vòng tròn bằng cách sử dụng các đường cong Bezier.

Để hoàn thành các câu trả lời khác: đối với đường cong Bezier với ncác phân đoạn khoảng cách tối ưu đến các điểm kiểm soát, theo nghĩa là giữa đường cong nằm trên chính đường tròn, là (4/3)*tan(pi/(2n)).

công thức cho n phân đoạn

Vì vậy, cho 4 điểm nó là (4/3)*tan(pi/8) = 4*(sqrt(2)-1)/3 = 0.552284749831.

Trường hợp 4 điểm


2
Theo khoảng cách tối ưu, bạn đang tối ưu hóa loại chỉ số nào? Như được chỉ ra trong Gần đúng một vòng tròn với các đường cong Bézier lập phương , độ lệch cực đại thấp nhất có thể đạt được bằng một giá trị khác. Bạn có thể cung cấp một số liên kết xác định "tối ưu" có nghĩa là gì trong trường hợp của bạn, hoặc công thức được suy ra như thế nào?
Suma

1
@Suma, điều này không tối ưu cho một số khoảng cách. Nó là tối ưu để có giữa của đường cong trên đường tròn. Và chắc chắn có thể được làm tốt hơn nếu bạn đặt một tiêu chí khác.
Kpym

2
ĐỒNG Ý. Tôi sẽ cố gắng diễn đạt lại: "khoảng cách đến các điểm kiểm soát sao cho giữa đường cong nằm trên chính đường tròn". Tôi thấy đây là một quyết định hợp lệ (đủ tốt và dễ tính toán), nhưng tôi sẽ không gọi nó là tối ưu (ít nhất không phải là không viết nó là tối ưu theo nghĩa nào).
Suma

1
Vâng, vì cái này có độ lệch tối đa là + 0,027% và độ lệch tối thiểu là -0 so với vòng tròn thực. Nó chỉ lớn hơn vòng tròn thực, nên tính gần đúng được cải thiện tốt hơn được thực hiện bằng cách di chuyển C xuống một nửa 0,027%. Tuy nhiên, nếu bạn muốn các điểm giữa trên hình tròn, đây chắc chắn là cách để làm điều đó.
Tatarize

2
@ Legends2k Tôi sử dụng LaTeX với TikZ để tạo tệp PDF mà sau đó tôi chuyển đổi sang PNG.
Kpym

34

Được đề cập trong comp.graphics.faq

Trích:

Chủ đề 4.04: Làm cách nào để ghép một đường cong Bezier vào một đường tròn?

Điều thú vị là các đường cong Bezier có thể xấp xỉ một vòng tròn nhưng không hoàn toàn phù hợp với một vòng tròn. Một phép gần đúng phổ biến là sử dụng bốn beziers để mô hình hóa một vòng tròn, mỗi beziers có các điểm điều khiển cách các điểm cuối một khoảng d = r * 4 * (sqrt (2) -1) / 3 (trong đó r là bán kính vòng tròn), và trong một phương tiếp tuyến với đường tròn tại các điểm cuối. Điều này sẽ đảm bảo các điểm giữa của Beziers nằm trên đường tròn và đạo hàm cấp một là liên tục.
Sai số xuyên tâm trong phép tính gần đúng này sẽ là khoảng 0,0273% bán kính của vòng tròn.

Michael Goldapp, "Tính gần đúng của cung tròn bằng đa thức khối" Thiết kế Hình học có Sự hỗ trợ của Máy tính (# 8 1991 trang.227-238)

Tor Dokken và Morten Daehlen, "Phương pháp gần đúng của đường tròn bằng đường cong Bezier liên tục độ cong" Thiết kế Hình học có Sự hỗ trợ của Máy tính (# 7 1990 trang 33-41). http://www.sciasedirect.com/science/article/pii/016783969090019N (bài viết không miễn phí)

Ngoài ra, hãy xem bài viết không có tường phí tại http://spencermortensen.com/articles/bezier-circle/

Trình duyệt và Phần tử Canvas.

Lưu ý rằng một số trình duyệt sử dụng đường cong Bezier cho vòng cung vẽ canvas của họ, Chrome sử dụng (tại thời điểm hiện tại) cách tiếp cận 4 khu vực và Safari sử dụng phương pháp tiếp cận 8 khu vực, sự khác biệt chỉ đáng chú ý ở độ phân giải cao, vì 0,0273% đó, và cũng chỉ thực sự hiển thị khi các cung được vẽ song song và lệch pha nhau, bạn sẽ nhận thấy các cung dao động từ một vòng tròn thực. Hiệu ứng này cũng đáng chú ý hơn khi đường cong hoạt động xung quanh tâm xuyên tâm của nó, bán kính 600px thường là kích thước mà nó sẽ tạo ra sự khác biệt.

Một số API vẽ nhất định không có kết xuất vòng cung thực sự, vì vậy chúng cũng sử dụng các đường cong Bezier, ví dụ: nền tảng Flash không có api vẽ vòng cung, vì vậy bất kỳ khung công tác nào cung cấp cung cấp thường sử dụng cùng một cách tiếp cận đường cong Bezier.

Lưu ý rằng công cụ SVG trong trình duyệt có thể sử dụng một phương pháp vẽ khác.

Các nền tảng khác

Dù bạn đang cố gắng sử dụng nền tảng nào, bạn cũng nên kiểm tra xem cách vẽ vòng cung được thực hiện như thế nào, vì vậy bạn có thể dự đoán các lỗi trực quan như thế này và điều chỉnh.


Cảm ơn, tôi sẽ thay thế nó.
ocodo

31

Các câu trả lời cho câu hỏi là rất tốt, vì vậy có rất ít để bổ sung. Lấy cảm hứng từ điều đó, tôi bắt đầu thực hiện một thí nghiệm để xác nhận trực quan giải pháp, bắt đầu với bốn đường cong Bézier, giảm số đường cong xuống còn một. Thật ngạc nhiên khi tôi phát hiện ra rằng với ba đường cong Bézier, hình tròn trông đủ đẹp đối với tôi, nhưng việc xây dựng hơi phức tạp. Trên thực tế, tôi đã sử dụng Inkscape để đặt xấp xỉ Bézier rộng 1 pixel màu đen trên một vòng tròn rộng 3 pixel màu đỏ (do Inkscape sản xuất). Để làm rõ hơn, tôi đã thêm các đường và bề mặt màu xanh lam hiển thị các hộp giới hạn của các đường cong Bézier.

Để xem chính bạn, tôi đang trình bày kết quả của mình:

Biểu đồ 1 đường cong (trông giống như một giọt nước bị ép ở một góc, chỉ để hoàn thiện):nhập mô tả hình ảnh ở đây

Biểu đồ 2 đường cong:nhập mô tả hình ảnh ở đây

Biểu đồ 3 đường cong:nhập mô tả hình ảnh ở đây

Biểu đồ 4 đường cong: nhập mô tả hình ảnh ở đây

(Tôi muốn đặt SVG hoặc PDF ở đây, nhưng điều đó không được hỗ trợ)


1
Hiện tại, svg có thể được bao gồm dưới dạng đoạn mã html. Hãy xem ví dụ câu trả lời này: stackoverflow.com/a/32162431
TS

1
@TS: Khi tôi cố gắng thay thế đồ họa bằng SVG mà tôi có, tôi nhận ra rằng tôi đã đánh mất những cái đó với một thanh USB đã bị đánh cắp vào đầu năm nay. Nếu thời gian cho phép, tôi sẽ cố gắng tạo lại chúng sớm. Tuy nhiên, nếu SVG có thể được thêm vào dưới dạng mã XML (và không được hiển thị dưới dạng đồ họa) thì điều đó không có ý nghĩa gì ở đây.
U. Windl

Nếu trình duyệt của bạn hỗ trợ svg, thì hình ảnh sẽ được hiển thị ngay khi bạn nhấp vào "Chạy đoạn mã" (dường như nút đó không khả dụng trên phiên bản di động của stackoverflow ...). Xem trong câu trả lời tôi đã liên kết.
TS

1
@TS: Đối với các tệp dài hơn, IMHO quá xấu.
U. Windl,

9

Đã có nhiều câu trả lời nhưng tôi đã tìm thấy một bài báo trực tuyến nhỏ với cách tính gần đúng khối vuông góc của một đường tròn. Theo đường tròn đơn vị c = 0,55191502449 trong đó c là khoảng cách từ các điểm chặn trục dọc theo các tiếp tuyến đến các điểm kiểm soát.

Là một góc phần tư duy nhất cho vòng tròn đơn vị với hai tọa độ giữa là các điểm kiểm soát. (0,1),(c,1),(1,c),(1,0)

Sai số xuyên tâm chỉ là 0,019608% vì vậy tôi chỉ cần thêm nó vào danh sách các câu trả lời này.

Bài viết có thể được tìm thấy tại đây Tính gần đúng một đường tròn với các đường cong Bézier lập phương


5
Bạn đã đọc luận thuyết xuất sắc này về Đường cong Bezier của Mike 'Pomax' Kamermans của Stackoverflow chưa . Nó rất đáng để đọc! :-)
markE

1
@markE Cảm ơn bạn rất nhiều về liên kết đó, đó là một trong những luận thuyết "xuất sắc nhất" mà tôi từng thấy về chủ đề này. Nóng lòng muốn có cơ hội xem qua chi tiết ..: D cảm ơn ...
Blindman67

1
Vì vậy, với lỗi 0,019608%, đồ họa sẽ bị lỗi 4 pixel khi bán kính vượt quá 2551 pixel trong một vòng tròn thay vì 0,027253% khủng khiếp đó, nơi chúng ta là một nửa pixel lỗi (nơi công cụ đồ họa sẽ thay đổi pixel) ở 1835 px gây ra lỗi 2 pixel!
Tatarize

@Tatarize Bài báo không nói rõ sai số đo như thế nào, nó nói độ trôi xuyên tâm tối đa? Tôi cho rằng sai số được giảm thiểu dọc theo đường cong 0 <= t <= 1 để khớp với góc phần tư 0 <= pheta <= Pi / 2 tại t = 0 = 1/2 = 1 bằng pheta = 0 = Pi / 4 = Pi / 4 sai số là 0,019608% và sai số lớn nhất tại t = ~ 0,1822 & t = ~ 0,8177 là 0,019608% (dấu hiệu?) Nhưng tại các điểm này t không bằng pheta thì sai số có bao gồm độ lệch góc không? . 4pixel có thể đúng hoặc không. Các lỗi có thể sai, do đó lỗi <2pix cho r = 2551. Rất nhiều câu hỏi mà sẽ cần phải điều tra
Blindman67

Tôi khá chắc chắn rằng đã xem xét đường cong lỗi rằng điều chỉnh đã cho chỉ đơn giản là di chuyển điểm xuống đủ để gây ra lỗi tối đa phía trên đường cung bằng với lỗi tối đa bên dưới đường cung. Có nghĩa là chúng tôi thay đổi đường cong xuống một chút để tất cả các lỗi không phải là tích cực. Điều chỉnh này có nghĩa là chúng ta đang vượt qua đường vòng cung 4 lần, với 4 điểm sai số tối đa. Khi đoạn thẳng ban đầu có 2 điểm, đó là lúc t = 0,25 và t = 0,75. Với các điều chỉnh, nó sẽ ở t = .125, t = .375 t = .625 t = .875. Điều này giả định rằng chúng tôi đang sử dụng các pixel đặc và không khử răng cưa sẽ thay đổi ở 14px.
Tatarize

8

Điều đó là không thể. Bezier là một hình khối (ít nhất là ... thông dụng nhất là). Một hình tròn không thể được biểu diễn chính xác bằng một hình khối, bởi vì một hình tròn chứa một căn bậc hai trong phương trình của nó. Do đó, bạn phải tính gần đúng.

Để làm điều này, bạn phải chia vòng kết nối của mình theo n-tants (ví dụ: dãy số, số bát phân). Đối với mỗi n-tant, bạn sử dụng điểm đầu tiên và điểm cuối cùng làm điểm đầu tiên và điểm cuối cùng của đường cong Bezier. Đa giác Bezier yêu cầu hai điểm bổ sung. Để nhanh chóng, tôi sẽ lấy các tiếp tuyến của đường tròn cho mỗi điểm cực trị của n-tant và chọn hai điểm làm giao điểm của hai tiếp tuyến (về cơ bản đa giác Bezier của bạn là một tam giác). Tăng số lượng quần lót n để phù hợp với độ chính xác của bạn.


4
Có thể được, miễn là bạn sử dụng vô số đường cong bezier, có độ dài bằng không. Về cơ bản là vô số điểm, hay đúng hơn chỉ là một đường cong.
Tatarize


7

Đối với những người chỉ đang tìm kiếm mã:

https://jsfiddle.net/nooorz24/2u9forep/12/

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");

function drawBezierOvalQuarter(centerX, centerY, sizeX, sizeY) {
    ctx.beginPath();
    ctx.moveTo(
    	centerX - (sizeX),
        centerY - (0)
    );
    ctx.bezierCurveTo(
    	centerX - (sizeX),
        centerY - (0.552 * sizeY),
        centerX - (0.552 * sizeX),
        centerY - (sizeY),
        centerX - (0),
        centerY - (sizeY)
    );
	ctx.stroke();
}

function drawBezierOval(centerX, centerY, sizeX, sizeY) {
    drawBezierOvalQuarter(centerX, centerY, -sizeX, sizeY);
    drawBezierOvalQuarter(centerX, centerY, sizeX, sizeY);
    drawBezierOvalQuarter(centerX, centerY, sizeX, -sizeY);
    drawBezierOvalQuarter(centerX, centerY, -sizeX, -sizeY);
}

function drawBezierCircle(centerX, centerY, size) {
    drawBezierOval(centerX, centerY, size, size)
}

drawBezierCircle(200, 200, 64)
<canvas id="myCanvas" width="400" height="400" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>

Điều này cho phép vẽ vòng tròn được tạo ra từ 4 đường cong Bezier. Được viết bằng JS nhưng có thể dễ dàng dịch sang bất kỳ ngôn ngữ nào khác


Điều đó rất hữu ích, cảm ơn! Cần thay đổi điều gì để đưa 4 phân đoạn vào thứ tự? Tôi cần viết văn bản dọc theo một đường dẫn, nhưng bây giờ nó nằm rải rác xung quanh 4 phân đoạn
Alexa

1

Tôi không chắc mình có nên mở câu hỏi mới không vì đây là về khoảng cách gần nhưng tôi quan tâm đến công thức chung để lấy điểm kiểm soát cho Bezier ở bất kỳ mức độ nào và tôi tin rằng nó phù hợp với câu hỏi này. Tất cả các giải pháp tôi tìm thấy trên web chỉ dành cho đường cong khối hoặc được trả tiền hoặc thậm chí tôi không hiểu (tôi không giỏi toán lắm). Vì vậy, tôi quyết định cố gắng giải quyết vấn đề này một mình. Tôi đã nghiên cứu khoảng cách của điểm điều khiển từ tâm của một vòng tròn phụ thuộc vào góc đã cho và cho đến nay tôi thấy rằng:

nhập mô tả hình ảnh ở đây

Đâu Nlà số điểm kiểm soát cho đường cong đơn và αlà góc cung tròn.

Đối với đường cong bậc hai, nó có thể được đơn giản hóa thành l ≈ r + r * PI*0.1 * pow(α/90, 2) The PI*0.1là một dự đoán - Tôi không tính được giá trị hoàn hảo nhưng nó khá gần. Điều này hoạt động hợp lý cho đường cong với 1-2 điểm kiểm soát cho sai số bán kính khoảng 0,2% cho đường cong hình khối. Đối với các đường cong mức độ cao hơn, sự mất độ chính xác là điều đáng chú ý. Với 3 điểm điều khiển, đường cong trông tương tự như bậc hai nên rõ ràng tôi đang bỏ lỡ điều gì đó nhưng tôi không thể tìm ra và phương pháp này nói chung phù hợp với nhu cầu của tôi lúc này. Đây là bản demo .


Bạn sử dụng phần mềm nào để tạo hình ảnh này?
Qian Sijianhao

1
Ảnh chụp màn hình từ bản demo + Math viết bảng điều khiển của tôi (hoặc tuy nhiên cái tên được dịch) từ win 7 + MS Paint
Paweł Audionysos

0

Xin lỗi vì đã mang lại điều này một trở lại từ cõi chết, nhưng tôi tìm thấy bài viết này rất hữu ích cùng với này trang trong đến với một công thức có thể mở rộng.

Về cơ bản, bạn có thể tạo một vòng tròn gần bằng một công thức cực kỳ đơn giản cho phép bạn sử dụng bất kỳ số lượng đường cong Bezier nào trên 4: Distance = radius * stepAngle / 3

Đâu Distancelà khoảng cách giữa điểm điều khiển Bezier và điểm cuối gần nhất của cung tròn, bán kính là radiusđường tròn vàstepAngle là góc giữa 2 đầu của cung được biểu diễn bằng 2π / (số đường cong).

Vì vậy, để đạt được nó trong một lần: Distance = radius * 2π / (the number of curves) / 3


1
Đây không phải là giá trị gần đúng nhất của một đường tròn. Tốt nhất là Distance = (4/3)*tan(pi/2n). Đối với số lượng cung lớn, nó gần như giống nhau bởi vì tan(pi/2)~pi/2n, nhưng ví dụ đối với n=4(trường hợp được sử dụng nhiều nhất) công thức của bạn đưa ra Distance=0.5235...nhưng công thức tối ưu là Distance=0.5522... (vì vậy bạn có sai số ~ 5%).
Kpym

-2

Đó là một ước tính nặng trông hợp lý hoặc khủng khiếp tùy thuộc vào độ phân giải và độ chính xác nhưng tôi sử dụng sqrt (2) / 2 x radius làm điểm kiểm soát của mình. Tôi đã đọc một văn bản khá dài về cách con số đó được bắt nguồn và nó đáng đọc nhưng công thức ở trên là nhanh và bẩn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.