Tôi nhận thấy điều này đã được trả lời trong khi trước đây nhưng tôi đang giải quyết cùng một vấn đề và tôi không thể tìm thấy giải pháp khả thi hoàn toàn có thể sử dụng được. Lưu ý rằng các hộp của tôi là axis aligned, điều này không được OP xác định rõ ràng. Các giải pháp dưới đây là hoàn toàn chung chung, và sẽ làm việc cho bất kỳ số lượng các nút giao (không chỉ có hai). Lưu ý rằng nếu hộp của bạn không được căn chỉnh theo trục (nhưng các hộp có góc vuông, thay vì chung là quads), bạn có thể tận dụng vòng tròn tròn, xoay tọa độ của mọi thứ sao cho hộp kết thúc theo trục và sau đó sử dụng mã này.
Tôi muốn sử dụng tích hợp - điều đó có vẻ như là một ý tưởng hay. Hãy bắt đầu với viết một công thức rõ ràng cho âm mưu một vòng tròn:
x = center.x + cos(theta) * radius
y = center.y + sin(theta) * radius
^
|
|**### **
| #* # * * x
|# * # * # y
|# * # *
+-----------------------> theta
* # * #
* # * #
* #* #
***###
này là tốt đẹp, nhưng tôi không thể để tích hợp các khu vực của vòng tròn đó qua x
hoặc y
; đó là những số lượng khác nhau.Tôi chỉ có thể tích hợp trên các góc theta
, năng suất các lát bánh pizza. Không phải những gì tôi muốn. Hãy cố gắng thay đổi các đối số:
(x - center.x)/radius = cos(theta) // the 1st equation
theta = acos((x - center.x)/radius) // value of theta from the 1st equation
y = center.y + sin(acos((x - center.x)/radius)) * radius // substitute to the 2nd equation
Điều đó giống như vậy. Bây giờ cho phạm vi của x
, tôi có thể tích hợp trên y
, để có được một khu vực của nửa trên của một vòng tròn. Điều này chỉ giữ cho x
trong [center.x - radius, center.x + radius]
(các giá trị khác sẽ gây ra kết quả đầu ra ảo) nhưng chúng tôi biết rằng khu vực bên ngoài phạm vi đó bằng 0, do đó được xử lý dễ dàng. Giả sử vòng tròn đơn vị cho đơn giản, chúng tôi luôn có thể cắm trung tâm và bán kính quay lại sau trên:
y = sin(acos(x)) // x in [-1, 1]
y = sqrt(1 - x * x) // the same thing, arguably faster to compute http://www.wolframalpha.com/input/?i=sin%28acos%28x%29%29+
^y
|
***|*** <- 1
**** | ****
** | **
* | *
* | *
----|----------+----------|-----> x
-1 1
Chức năng này thực sự có thể thiếu trong pi/2
, vì nó là một nửa trên của một vòng tròn đơn vị (diện tích nửa vòng tròn là pi * r^2/2
và chúng tôi đã nói đơn vị, có nghĩa là r = 1
). Bây giờ chúng ta có thể tính toán diện tích giao điểm của một nửa vòng tròn và một hộp cao vô cùng, đứng trên trục x (trung tâm của vòng tròn cũng nằm trên trục x) bằng cách tích hợp trên y
:
f(x): integral(sqrt(1 - x * x) * dx) = (sqrt(1 - x * x) * x + asin(x))/2 + C // http://www.wolframalpha.com/input/?i=sqrt%281+-+x*x%29
area(x0, x1) = f(max(-1, min(1, x1))) - f(max(-1, min(1, x0))) // the integral is not defined outside [-1, 1] but we want it to be zero out there
~ ~
| ^|
| | |
| ***|*** <- 1
****###|##|****
**|######|##| **
* |######|##| *
* |######|##| *
----|---|------+--|-------|-----> x
-1 x0 x1 1
này có thể không hữu ích lắm, vì hộp cao vô cùng không phải là thứ chúng ta muốn. Chúng ta cần phải thêm một tham số hơn để có thể giải phóng mép dưới cùng của hộp cao vô hạn:
g(x, h): integral((sqrt(1 - x * x) - h) * dx) = (sqrt(1 - x * x) * x + asin(x) - 2 * h * x)/2 + C // http://www.wolframalpha.com/input/?i=sqrt%281+-+x*x%29+-+h
area(x0, x1, h) = g(min(section(h), max(-section(h), x1))) - g(min(section(h), max(-section(h), x0)))
~ ~
| ^|
| | |
| ***|*** <- 1
****###|##|****
**|######|##| **
* +------+--+ * <- h
* | *
----|---|------+--|-------|-----> x
-1 x0 x1 1
đâu h
là (dương tính) khoảng cách cạnh đáy của hộp vô hạn của chúng tôi từ trục x . Chức năng section
tính (dương tính) vị trí giao nhau của đường tròn đơn vị với các đường ngang do y = h
và chúng ta có thể định nghĩa nó bằng cách giải quyết:
sqrt(1 - x * x) = h // http://www.wolframalpha.com/input/?i=sqrt%281+-+x+*+x%29+%3D+h
section(h): (h < 1)? sqrt(1 - h * h) : 0 // if h is 1 or above, then the section is an empty interval and we want the area integral to be zero
^y
|
***|*** <- 1
**** | ****
** | **
-----*---------+---------*------- y = h
* | *
----||---------+---------||-----> x
-1| |1
-section(h) section(h)
Bây giờ chúng ta có thể nhận được điều đang xảy ra. Vì vậy, cách tính diện tích giao nhau của một hộp hữu hạn giao nhau với một vòng tròn đơn vị phía trên trục x:
area(x0, x1, y0, y1) = area(x0, x1, y0) - area(x0, x1, y1) // where x0 <= x1 and y0 <= y1
~ ~ ~ ~
| ^| | ^|
| | | | | |
| ***|*** | ***|***
****###|##|**** ****---+--+**** <- y1
**|######|##| ** ** | **
* +------+--+ * <- y0 * | *
* | * * | *
----|---|------+--|-------|-----> x ----|---|------+--|-------|-----> x
x0 x1 x0 x1
^
|
***|***
****---+--+**** <- y1
**|######|##| **
* +------+--+ * <- y0
* | *
----|---|------+--|-------|-----> x
x0 x1
Thật tuyệt. Vậy làm thế nào về một hộp mà không phải là trên trục x? Tôi muốn nói không phải tất cả các hộp đều có. Ba trường hợp đơn giản nảy sinh:
- hộp là ở trên trục x (sử dụng phương trình trên)
- hộp nằm dưới trục x (lật dấu tọa độ y và sử dụng các phương trình ở trên)
- hộp là giao nhau với trục x (chia hộp thành phần trên và nửa dưới, tính diện tích của cả hai bằng cách sử dụng ở trên và tổng hợp chúng)
Đủ dễ dàng? Hãy viết một số mã:
float section(float h, float r = 1) // returns the positive root of intersection of line y = h with circle centered at the origin and radius r
{
assert(r >= 0); // assume r is positive, leads to some simplifications in the formula below (can factor out r from the square root)
return (h < r)? sqrt(r * r - h * h) : 0; // http://www.wolframalpha.com/input/?i=r+*+sin%28acos%28x+%2F+r%29%29+%3D+h
}
float g(float x, float h, float r = 1) // indefinite integral of circle segment
{
return .5f * (sqrt(1 - x * x/(r * r)) * x * r + r * r * asin(x/r) - 2 * h * x); // http://www.wolframalpha.com/input/?i=r+*+sin%28acos%28x+%2F+r%29%29+-+h
}
float area(float x0, float x1, float h, float r) // area of intersection of an infinitely tall box with left edge at x0, right edge at x1, bottom edge at h and top edge at infinity, with circle centered at the origin with radius r
{
if(x0 > x1)
std::swap(x0, x1); // this must be sorted otherwise we get negative area
float s = section(h, r);
return g(max(-s, min(s, x1)), h, r) - g(max(-s, min(s, x0)), h, r); // integrate the area
}
float area(float x0, float x1, float y0, float y1, float r) // area of the intersection of a finite box with a circle centered at the origin with radius r
{
if(y0 > y1)
std::swap(y0, y1); // this will simplify the reasoning
if(y0 < 0) {
if(y1 < 0)
return area(x0, x1, -y0, -y1, r); // the box is completely under, just flip it above and try again
else
return area(x0, x1, 0, -y0, r) + area(x0, x1, 0, y1, r); // the box is both above and below, divide it to two boxes and go again
} else {
assert(y1 >= 0); // y0 >= 0, which means that y1 >= 0 also (y1 >= y0) because of the swap at the beginning
return area(x0, x1, y0, r) - area(x0, x1, y1, r); // area of the lower box minus area of the higher box
}
}
float area(float x0, float x1, float y0, float y1, float cx, float cy, float r) // area of the intersection of a general box with a general circle
{
x0 -= cx; x1 -= cx;
y0 -= cy; y1 -= cy;
// get rid of the circle center
return area(x0, x1, y0, y1, r);
}
Và một số xét nghiệm đơn vị cơ bản:
printf("%f\n", area(-10, 10, -10, 10, 0, 0, 1)); // unit circle completely inside a huge box, area of intersection is pi
printf("%f\n", area(-10, 0, -10, 10, 0, 0, 1)); // half of unit circle inside a large box, area of intersection is pi/2
printf("%f\n", area(0, 10, -10, 10, 0, 0, 1)); // half of unit circle inside a large box, area of intersection is pi/2
printf("%f\n", area(-10, 10, -10, 0, 0, 0, 1)); // half of unit circle inside a large box, area of intersection is pi/2
printf("%f\n", area(-10, 10, 0, 10, 0, 0, 1)); // half of unit circle inside a large box, area of intersection is pi/2
printf("%f\n", area(0, 1, 0, 1, 0, 0, 1)); // unit box covering one quadrant of the circle, area of intersection is pi/4
printf("%f\n", area(0, -1, 0, 1, 0, 0, 1)); // unit box covering one quadrant of the circle, area of intersection is pi/4
printf("%f\n", area(0, -1, 0, -1, 0, 0, 1)); // unit box covering one quadrant of the circle, area of intersection is pi/4
printf("%f\n", area(0, 1, 0, -1, 0, 0, 1)); // unit box covering one quadrant of the circle, area of intersection is pi/4
printf("%f\n", area(-.5f, .5f, -.5f, .5f, 0, 0, 10)); // unit box completely inside a huge circle, area of intersection is 1
printf("%f\n", area(-20, -10, -10, 10, 0, 0, 1)); // huge box completely outside a circle (left), area of intersection is 0
printf("%f\n", area(10, 20, -10, 10, 0, 0, 1)); // huge box completely outside a circle (right), area of intersection is 0
printf("%f\n", area(-10, 10, -20, -10, 0, 0, 1)); // huge box completely outside a circle (below), area of intersection is 0
printf("%f\n", area(-10, 10, 10, 20, 0, 0, 1)); // huge box completely outside a circle (above), area of intersection is 0
Kết quả của việc này là:
3.141593
1.570796
1.570796
1.570796
1.570796
0.785398
0.785398
0.785398
0.785398
1.000000
-0.000000
0.000000
0.000000
0.000000
Mà dường như đúng với tôi. Bạn có thể muốn nội tuyến các chức năng nếu bạn không tin tưởng trình biên dịch của bạn để làm điều đó cho bạn.
Điều này sử dụng 6 sqrt, 4 asin, 8 div, 16 mul và 17 bổ sung cho các hộp không giao nhau với trục x và gấp đôi số đó (và 1 thêm) cho hộp làm. Lưu ý rằng các phân chia là bởi bán kính và có thể được giảm xuống hai đơn vị và một loạt các phép nhân. Nếu hộp được đề cập giao cắt trục x nhưng không giao nhau với trục y, bạn có thể xoay mọi thứ theo pi/2
và thực hiện phép tính theo giá gốc.
Tôi đang sử dụng nó làm tài liệu tham khảo để gỡ lỗi trình chỉnh sửa vòng tròn antialiased chính xác subpixel. Nó là chậm như địa ngục :), tôi cần phải tính toán diện tích giao nhau của mỗi điểm ảnh trong hộp giới hạn của vòng tròn với vòng tròn để có được alpha. Bạn có thể thấy rằng nó hoạt động và không có hiện vật số dường như xuất hiện. Hình bên dưới là đồ thị của một loạt các vòng tròn có bán kính tăng từ 0,3 px đến khoảng 6 px, được bố trí theo hình xoắn ốc.
Họ chỉ có 2 điểm giao lộ? Hay họ có ít nhất 2 điểm giao nhau? – bigmonachus
Bạn có cần tính diện tích theo đơn vị vuông hoặc trả về một tập hợp các đoạn đường xác định khu vực không? – Leonard
Nếu một trong hai bên kia, hoặc nếu cả hai không chồng lên nhau, thì không có điểm giao nhau. Nếu đường tròn tiếp xúc với bất kỳ cạnh nào của hình chữ nhật, thì chỉ có một điểm giao nhau. – duffymo