Matlab:为什么填充函数不填充两个圆圈之间的区域?
Matlab: Why is the fill function not filling the area between two circles?
我试图在 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
我最终得到的是下图:
但是,它应该显示为这个图像:
为什么没有像示例文章中那样填充区域?
如果您有 Mapping Toolbox,您可以使用 polybool
to find the intersection between to polygones, and than patch
(which dosen't require Mapping Toolbox, and is better than fill
) to draw it. The folowing code works even without the first 2 lines that use poly2cw
,但它会发出一些警告。这可以通过 poly2cw
转换来解决:
[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
问题中的代码无法运行,因为它在 fillx
和 filly
中的点的顺序有一些错误。我们可以看到,如果我们将 'EdgeColor'
设置为可见,并沿着补丁的外围线(见下图,这里减少到 20 个点,用于说明)。我们可以清楚地看到,要填充的多边形的点排列在圆之间的'zig-zag'中,所以它根本没有面积。我已经对从每个圆中取出的多边形顶点进行了编号,以演示 fill
函数读取它们的顺序。
为了用颜色填充圆之间的所有交点,我们需要通过圆上相交的点(in1
和 in2
)来定义 'polygon'正确的顺序。这意味着如果假想的铅笔按照给定的顺序在它们之间画一条线,我们希望它们形成一个闭合的形状。像这样:
我们从其中一个圆圈中的 1 开始,一直持续到该圆圈上的数字结束,然后移动到另一个圆圈中的 1,当我们到达第二个圆圈的尽头时,我们关闭多边形将最后一点连接到第一个点。正如您在上图中看到的那样,圆圈的起点和终点非常接近,所以我们得到两个数字在彼此之上。
如何正确排序点数?
我们首先按照问题中的描述获取 in1
和 in2
。我们来看看in1
:
in1 =
1 2 3 4 5 6 7 19 20
这些是c1
要取的点的索引,它们看起来是有序的,但包含一个间隙。这个差距是因为inpolygon
按照c1
中的顺序检查点,而c1
的起点在交集区域内。所以我们得到前 7 个点,然后我们离开交叉路口,当我们到达点 19 和 20 时我们返回。但是,对于我们的多边形,我们需要这些点从最近的点开始到其中一个地方圆相交的地方,然后绕着圆走,直到我们到达第二个交点。
为此,我们在积分顺序中查找 'gap':
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))];
但是,可能没有'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
现在我们需要做的就是连接 X1
和 X2
(对于圆圈 2),对于 Y
也是如此,并使用 patch
(类似于 fill
,但更好)绘制它:
patch([X1 X2],[Y1 Y2],'g','EdgeColor','none')
有 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
上面提到的所有内容都可以替换为在相交的顶点上使用 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')
我试图在 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
我最终得到的是下图:
但是,它应该显示为这个图像:
为什么没有像示例文章中那样填充区域?
如果您有 Mapping Toolbox,您可以使用 polybool
to find the intersection between to polygones, and than patch
(which dosen't require Mapping Toolbox, and is better than fill
) to draw it. The folowing code works even without the first 2 lines that use poly2cw
,但它会发出一些警告。这可以通过 poly2cw
转换来解决:
[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
问题中的代码无法运行,因为它在 fillx
和 filly
中的点的顺序有一些错误。我们可以看到,如果我们将 'EdgeColor'
设置为可见,并沿着补丁的外围线(见下图,这里减少到 20 个点,用于说明)。我们可以清楚地看到,要填充的多边形的点排列在圆之间的'zig-zag'中,所以它根本没有面积。我已经对从每个圆中取出的多边形顶点进行了编号,以演示 fill
函数读取它们的顺序。
为了用颜色填充圆之间的所有交点,我们需要通过圆上相交的点(in1
和 in2
)来定义 'polygon'正确的顺序。这意味着如果假想的铅笔按照给定的顺序在它们之间画一条线,我们希望它们形成一个闭合的形状。像这样:
我们从其中一个圆圈中的 1 开始,一直持续到该圆圈上的数字结束,然后移动到另一个圆圈中的 1,当我们到达第二个圆圈的尽头时,我们关闭多边形将最后一点连接到第一个点。正如您在上图中看到的那样,圆圈的起点和终点非常接近,所以我们得到两个数字在彼此之上。
如何正确排序点数?
我们首先按照问题中的描述获取 in1
和 in2
。我们来看看in1
:
in1 =
1 2 3 4 5 6 7 19 20
这些是c1
要取的点的索引,它们看起来是有序的,但包含一个间隙。这个差距是因为inpolygon
按照c1
中的顺序检查点,而c1
的起点在交集区域内。所以我们得到前 7 个点,然后我们离开交叉路口,当我们到达点 19 和 20 时我们返回。但是,对于我们的多边形,我们需要这些点从最近的点开始到其中一个地方圆相交的地方,然后绕着圆走,直到我们到达第二个交点。
为此,我们在积分顺序中查找 'gap':
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))];
但是,可能没有'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
现在我们需要做的就是连接 X1
和 X2
(对于圆圈 2),对于 Y
也是如此,并使用 patch
(类似于 fill
,但更好)绘制它:
patch([X1 X2],[Y1 Y2],'g','EdgeColor','none')
有 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
上面提到的所有内容都可以替换为在相交的顶点上使用 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')