供日后参考,这是我编写的一些Matlab代码来解决这个问题:
https://uk.mathworks.com/matlabcentral/fileexchange/126645-intersection-of-polygon-and-circle
它或多或少地实现了Brian Moths的答案。
以下是代码:
function [A, pointList, isArc, AP] = polygonCircleIntersection(R, P)
nV = size(P, 2);
AP = 0;
for i = 1:nV
AP = AP + shoelace(P(:,i), P(:,mod(i,nV)+1));
end
if(AP<0)
error("Polygon must be in counter-clockwise order");
end
nT2 = sum(P.^2);
isOutside = nT2>R^2;
if(~any(isOutside))
A = 0;
for i = 1:nV
A = A + shoelace(P(:,i), P(:,mod(i,nV)+1));
end
pointList = P;
isArc = false(1,nV);
return;
end
shiftK = 1-find(isOutside,1,"first");
P = circshift(P,shiftK, 2);
isOutside = circshift(isOutside,shiftK, 2);
pointList = [];
isArc = [true];
outsideCircle = true;
iP = 1;
for i = 1:nV
x0 = P(:,i);
d = P(:,mod(i,nV)+1)-x0;
[xI, onCircle] = segmentCircleIntersection(x0, d, R);
pointList = [pointList xI];
if(~isempty(xI))
isArc(iP) = outsideCircle;
isArc(iP+1) = false;
outsideCircle = onCircle(2);
iP = iP + 2;
end
end
if(isempty(pointList) && all(isOutside))
polygonContainsOrigin = inpolygon(0,0,P(1,:), P(2,:));
if(polygonContainsOrigin)
A = pi*R^2;
pointList = [1;0];
else
A = 0;
pointList = [];
isArc = [];
end
return;
end
if(isempty(pointList) && any(isOutside) && ~all(isOutside))
error("there are no intersections, but some points are inside and others outside")
end
if(any(isArc & circshift(isArc, 1)))
error("there can't be two arcs in a row")
end
nI = size(pointList, 2);
A = 0;
for i = 1:nI
iPrev = mod(i-2,nI)+1;
xPrev = pointList(:, iPrev);
xi = pointList(:, i);
if(isArc(i))
thPrev = atan2(xPrev(2),xPrev(1));
thi = atan2(xi(2),xi(1));
dth = wrapTo2Pi(thi-thPrev);
if(dth == 2*pi), dth = 0; end
A = A + dth*R^2/2;
else
A = A + shoelace(xPrev, xi);
end
end
if(A<0 || A>pi*R^2 || A > AP)
error("invalid area")
end
end
function [xI, onCircle] = segmentCircleIntersection(x0, d, R)
a = sum(d.^2);
b = 2*x0'*d;
c = sum(x0.^2) - R^2;
D = b^2 - 4*a*c;
if(D<=0)
xI = [];
onCircle = [];
return
end
ll = (-b + [-1 1]*sqrt(D) )/(2*a);
if( ll(1) >= ll(2) )
error("A mathematical impossibility. Did you give this thing complex numbers or something?")
end
if( ll(2)<0 || ll(1)>1)
xI = [];
onCircle = [];
return
end
ll = max(0, ll);
ll = min(1, ll);
xI = x0 + ll.*d;
onCircle = [ll(1)>0 ll(2)<1];
end
function A = shoelace(p1, p2)
A = (p1(1)*p2(2) - p1(2)*p2(1))/2;
end