我试图在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
我最终得到的是以下图片:
但是,它应该显示为此图像:
为什么区域没有像示例文章那样被填充?
答案 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
答案 1 :(得分:0)
问题中的代码不起作用,因为它在fillx
和filly
中的点的顺序中存在一些错误。我们可以看到,如果我们将'EdgeColor'
设置为可见,并按照补丁的外围线(见下文,此处减少到20个点,为了说明)。我们可以清楚地看到要填充的多边形的点在圆圈之间以“之字形”排序,因此它根本没有区域。我已经对从每个圆圈中取出的多边形的顶点进行了编号,以演示fill
函数读取它们的顺序。
为了填充圆圈之间所有交点的颜色,我们需要按照正确顺序交叉(in1
和in2
)的圆上的点来定义“多边形”。这意味着如果假想的铅笔在它们之间以相同的顺序绘制一条线,我们希望它们形成一个封闭的形状。像这样:
我们从一个圆圈中的1开始并继续直到该圆圈上的数字结束,然后在另一个圆圈上移动到1,当我们到达第二个圆圈的末尾时,我们通过连接圆圈来关闭多边形最后一点指向第一个。正如你在上图所示,圆圈的起点和终点非常接近,所以我们得到2个数字。
我们如何正确订购积分?
我们首先按照问题中的描述获取in1
和in2
。我们来看看in1
:
in1 =
1 2 3 4 5 6 7 19 20
这些是来自c1
的点的索引,它们看起来是有序的,但是包含间隙。这个差距是因为inpolygon
按c1
中的顺序检查点,而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
现在我们需要连接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')