Matlab:为什么填充函数没有填充两个圆之间的区域?

时间:2017-07-04 17:37:11

标签: matlab matlab-figure fill

我试图在Matlab中填充两个圆圈之间的交叉区域。我从Matlab Central的this文章中复制并粘贴了这段代码。

t = linspace(0, 2*pi, 100);
cir = @(r,ctr) [r*cos(t)+ctr(1); r*sin(t)+ctr(2)]; % Circle Function
c1 = cir(1.0, [0; 0]);
c2 = cir(1.5, [1; 1]);
in1 = find(inpolygon(c1(1,:), c1(2,:), c2(1,:), c2(2,:))); % Circle #1 Points Inside Circle #2
in2 = find(inpolygon(c2(1,:), c2(2,:), c1(1,:), c1(2,:))); % Circle #2 Points Inside Circle #1
[fillx,ix] = sort([c1(1,in1) c2(1,in2)]); % Sort Points
filly = [c1(2,in1) (c2(2,in2))];
filly = filly(ix);
figure(1)
plot(c1(1,:), c1(2,:))
hold on
plot(c2(1,:), c2(2,:))
fill([fillx fliplr(fillx)], [filly fliplr(filly)], 'g', 'EdgeColor','none')
hold off
axis square

我最终得到的是以下图片:

enter image description here

但是,它应该显示为此图像:

enter image description here

为什么区域没有像示例文章那样被填充?

2 个答案:

答案 0 :(得分:2)

如果您有Mapping Toolbox,则可以使用polybool查找到多边形之间的交集,而不是patch(不需要Mapping Toolbox,并且优于fill)画它。即使没有使用poly2cw的前两行,下面的代码仍可正常工作,但它会发出一些警告。这可以通过poly2cw trasfomation:

来解决
[c1(1,:), c1(2,:)] = poly2cw(c1(1,:), c1(2,:)); % clock-wise transform
[c2(1,:), c2(2,:)] = poly2cw(c2(1,:), c2(2,:)); % clock-wise transform   
[xb, yb] = polybool('intersection',c1(1,:),c1(2,:),c2(1,:), c2(2,:));
plot(c1(1,:), c1(2,:))
hold on
plot(c2(1,:), c2(2,:))
patch(xb, yb, 1, 'FaceColor', 'g','EdgeColor','none')
axis equal

circle intersection

答案 1 :(得分:0)

问题中的代码不起作用,因为它在fillxfilly中的点的顺序中存在一些错误。我们可以看到,如果我们将'EdgeColor'设置为可见,并按照补丁的外围线(见下文,此处减少到20个点,为了说明)。我们可以清楚地看到要填充的多边形的点在圆圈之间以“之字形”排序,因此它根本没有区域。我已经对从每个圆圈中取出的多边形的顶点进行了编号,以演示fill函数读取它们的顺序。

enter image description here

为了填充圆圈之间所有交点的颜色,我们需要按照正确顺序交叉(in1in2)的圆上的点来定义“多边形”。这意味着如果假想的铅笔在它们之间以相同的顺序绘制一条线,我们希望它们形成一个封闭的形状。像这样:

enter image description here

我们从一个圆圈中的1开始并继续直到该圆圈上的数字结束,然后在另一个圆圈上移动到1,当我们到达第二个圆圈的末尾时,我们通过连接圆圈来关闭多边形最后一点指向第一个。正如你在上图所示,圆圈的起点和终点非常接近,所以我们得到2个数字。

我们如何正确订购积分?

我们首先按照问题中的描述获取in1in2。我们来看看in1

in1 =
     1     2     3     4     5     6     7    19    20

这些是来自c1的点的索引,它们看起来是有序的,但是包含间隙。这个差距是因为inpolygonc1中的顺序检查点,而c1的起点位于交叉区域内。所以我们得到前7个点,然后我们离开交叉点,当我们到达第19和第20点时我们返回。但是,对于我们的多边形,我们需要这些点从距其中一个点的最近点开始圆相交的地方,围绕圆圈,直到我们到达第二个交点。

为此,我们在点数顺序中寻找'缺口':

gap = find(diff(in1)>1);

并正确重新排序:

X1 = [c1(1,in1(gap+1:end)) c1(1,in1(1:gap))];
Y1 = [c1(2,in1(gap+1:end)) c1(2,in1(1:gap))];

但是,正如我们在in2中所看到的那样,可能没有“差距”:

in2 =
    11    12    13    14

所以我们需要在if内包装它以检查点是否需要重新排序:

if ~isempty(gap)
    X1 = [c1(1,in1(gap+1:end)) c1(1,in1(1:gap))];
    Y1 = [c1(2,in1(gap+1:end)) c1(2,in1(1:gap))];
else
    X1 = c1(1,in1);
    Y1 = c1(2,in1);
end

现在我们需要连接X1X2(对于圈子2),对Y进行连接,然后使用patch(其中就像fill,但更好)来绘制它:

patch([X1 X2],[Y1 Y2],'g','EdgeColor','none')

enter image description here

有20个点,圆圈实际上不是圆形,交叉点是部分着色的,所以这里是完整的代码,结果是200分:

t = linspace(0, 2*pi, 200);
cir = @(r,ctr) [r*cos(t)+ctr(1); r*sin(t)+ctr(2)]; % Circle Function
c1 = cir(1.0, [0; 0]);
c2 = cir(1.5, [1; 1]);
plot(c1(1,:), c1(2,:))
hold on
plot(c2(1,:), c2(2,:))
axis equal
in1 = find(inpolygon(c1(1,:), c1(2,:), c2(1,:), c2(2,:)));
in2 = find(inpolygon(c2(1,:), c2(2,:), c1(1,:), c1(2,:)));
gap = find(diff(in1)>1);
if ~isempty(gap)
    X1 = [c1(1,in1(gap+1:end)) c1(1,in1(1:gap))];
    Y1 = [c1(2,in1(gap+1:end)) c1(2,in1(1:gap))];
else
    X1 = c1(1,in1);
    Y1 = c1(2,in1);
end
gap = find(diff(in2)>1);
if ~isempty(gap)
    X2 = [c2(1,in2(gap+1:end)) c2(1,in2(1:gap))];
    Y2 = [c2(2,in2(gap+1:end)) c2(2,in2(1:gap))];
else
    X2 = c2(1,in2);
    Y2 = c2(2,in2);
end
patch([X1 X2],[Y1 Y2],'g','EdgeColor','none')
hold off 

enter image description here

上面提到的所有内容都可以替换为在相交的顶点上使用convhull并给出相同的结果:

x = [c1(1,in1) c2(1,in2)]; % all x's for intersecting vertices
y = [c1(2,in1) c2(2,in2)]; % all y's for intersecting vertices
k = convhull(x,y); % calculate the convex polygon
patch(x(k),y(k),'g','EdgeColor','none')