填充两个矩形之间的空白区域。

3
如何在两个矩形不垂直对齐时填充它们之间的空间。因此,如果一个矩形向上移动,则它和下一个矩形之间的间隙(在沿相同路径的所有矩形中)看起来很平滑。
示例:
当前: Ugly gap 期望: Desired look 我的当前绘图代码:
public override void Draw(Graphics g)
{
    for (int i = 0; i < this._Children.Count; i++)
    {
        this._Children[i].Draw(g);

        if (i != 0 && i + 1 < this._Children.Count)
        {
            if (this._Children[i].Y != this._Children[i + 1].Y)
            {
                 //Draw circle in gap between?
            }
        }
    }

    base.Draw(g);
}

底层绘制:

g.FillRectangle(this.Color, this.X, this.Y, this.Size.Width, this.Size.Height);
g.DrawRectangle(this.Outline, this.X, this.Y, this.Size.Width, this.Size.Height);

修改后:

在遵循Jim和评论者的建议后,我得到了以下内容。数学似乎有误,而且根本没有达到我想要的效果。

GraphicsPath path = new GraphicsPath();

for (int i = 0; i < this._Children.Count; i++)
{
    path.AddRectangle(this._Children[i].GetBoundingBox());

    if (i < this._Children.Count)
    {
        Block block = i == 0 ? (Block)this : this._Children[i - 1];

        float x = this._Children[i].X < block.X ? this._Children[i].X : block.X;
        float y = this._Children[i].Y > block.X ? this._Children[i].Y : block.Y;
        float width = System.Math.Abs(this._Children[i].X - block.X);
        float height = System.Math.Abs(this._Children[i].Y - block.Y);
        path.AddEllipse(x, y, width, height);
    }
}

g.FillPath(this._Children[0].Color, path);
g.DrawPath(this._Children[0].Outline, path);
base.Draw(g);

enter image description here

第二次编辑:一直在按照大家的建议进行编辑。现在Jim的代码可以工作了,但只有在你向上移动并开始向右移动时才能绘制。

现在根据TAW的建议,我得到了ArgumentInvalid,我认为这是因为rGap矩形的高度为0。

我按照TAW的实现方式进行了实现:

for (int i = 0; i < this._Children.Count; i++)
{
    this._Children[i].Draw(g);

    if (i + 1 < this._Children.Count)
    {
        Block block = i == 0 ? (Block)this : this._Children[i + 1];

        Rectangle rec = this._Children[i].GetBoundingBox();
        Rectangle rec2 = block.GetBoundingBox();
        Rectangle rGap = new Rectangle(Math.Min(rec.X, rec2.X), Math.Min(rec.Y, rec2.Y), 2 * Math.Abs(rec.Left - rec2.Left), 2 * Math.Abs(rec2.Top - rec.Top));

        GraphicsPath gp = new GraphicsPath();
        gp.AddRectangle(rec);
        gp.AddRectangle(rec2);
        gp.AddArc(rGap, 0, 360);

        gp.FillMode = FillMode.Winding;
        g.DrawPath(this._Children[i].Outline, gp);
        g.FillPath(this._Children[i].Color, gp);
    }
}

base.Draw(g);

编辑3: 在研究了一些问题后,我开发了自己的解决方案,虽然不是我想要的解决方案,但希望它可以帮助其他人。现在只需要将其转换为圆角即可。
代码:
for (int i = 0; i < this._Children.Count; i++)
{
    this._Children[i].Draw(g);

    Block block = i - 1 < 0 ? (Block)this : this._Children[i - 1];

    Rectangle rec = this._Children[i].GetBoundingBox();
    Rectangle rec2 = block.GetBoundingBox();
    Direction dir = this._Children[i].GetDirection(true);
    Direction dir2 = block.GetDirection(true);

    int minX = Math.Min(rec.X, rec2.X);
    int minY = Math.Min(rec.Y, rec2.Y);
    int maxX = Math.Max(rec.X, rec2.X);
    int maxY = Math.Max(rec.Y, rec2.Y);
    int diffX = maxX - minX;
    int diffY = maxY - minY;
    int width = this._Children[i].Size.Width;
    int height = this._Children[i].Size.Height;
    Rectangle fillRec = default(Rectangle);

    if ((dir == Direction.Right && dir2 == Direction.Down) || (dir == Direction.Up && dir2 == Direction.Left))
    {
        fillRec = new Rectangle(minX + width, minY, diffX, diffY);
    }
    else if ((dir == Direction.Down && dir2 == Direction.Left) || (dir == Direction.Right && dir2 == Direction.Up))
    {
        fillRec = new Rectangle(minX + width, (maxY + height) - diffY, diffX, diffY);
    }
    else if ((dir == Direction.Up && dir2 == Direction.Right) || (dir == Direction.Left && dir2 == Direction.Down))
    {
        fillRec = new Rectangle(minX, minY, diffX, diffY);
    }
    else if ((dir == Direction.Left && dir2 == Direction.Up) || (dir == Direction.Down && dir2 == Direction.Right))
    {
        fillRec = new Rectangle(minX, (maxY + height) - diffY, diffX, diffY);
    }

    if (fillRec != default(Rectangle))
    {
        g.FillRectangle(this._Children[i].Color, fillRec);
        g.DrawRectangle(this._Children[i].Outline, fillRec);
    }
}
base.Draw(g);

产生: 输入图像描述

2
你需要使用一个 GraphicsPath 对象。 - Rotem
我将其转换为图形路径,但如何填补间隙呢? - user1763295
你可以将一个圆形添加到路径中,并填充它并绘制其轮廓。 - TaW
我已经尝试过了,但并没有解决问题。我的数学肯定有问题(按照Jim说的来做),因为向上或向右移动时一切正常,但向下或向左移动时会在错误的位置绘制。此外,它也没有产生预期的效果,而是填充了一些空间。已更新原帖。 - user1763295
2个回答

2

这里是一个解决方案,用于绘制四个矩形的所有四个圆角。

我创建了四个重叠的矩形,它们之间有各种间隙,并将它们和弧线添加到一个GraphicsPath中,以填充间隙。

GraphicsPath GP = new GraphicsPath();

Rectangle fillGap(Rectangle R1, Rectangle R2, bool isTop, bool isLeft )
{ 
    int LeftMin    = Math.Min(R1.Left, R2.Left);
    int RightMax   = Math.Max(R1.Right, R2.Right);
    int TopMin     = Math.Min(R1.Top, R2.Top);
    int BotMax     = Math.Max(R1.Bottom, R2.Bottom);
    int RightGap   = 2 * Math.Abs(R1.Right - R2.Right);
    int LeftGap    = 2 * Math.Abs(R1.Left - R2.Left);
    int TopGap     = 2 * Math.Abs(R1.Top - R2.Top);
    int BotGap     = 2 * Math.Abs(R1.Bottom - R2.Bottom);

    Rectangle R = Rectangle.Empty; 
    if (isTop && isLeft) R = new Rectangle(LeftMin, TopMin, LeftGap, TopGap);
    if (isTop && !isLeft) 
        R = new Rectangle(RightMax - RightGap, TopMin, RightGap, TopGap);
    if (!isTop && !isLeft) 
        R = new Rectangle(RightMax - RightGap, BotMax  - BotGap , RightGap, BotGap );
    if (!isTop && isLeft) 
        R = new Rectangle(LeftMin, BotMax  - BotGap , LeftGap, BotGap );
     return R;
}

private void button1_Click(object sender, EventArgs e)
{
    Rectangle Rtop = new Rectangle(20, 10, 200, 40);
    Rectangle Rbottom = new Rectangle(20, 200, 200, 40);
    Rectangle Rleft = new Rectangle(10, 20, 40, 200);
    Rectangle Rright = new Rectangle(210, 20, 40, 200);

    GP = new GraphicsPath(); 
    GP.FillMode = FillMode.Winding;

    GP.AddRectangle(Rtop);
    GP.AddRectangle(Rleft);
    GP.AddRectangle(Rbottom);
    GP.AddRectangle(Rright);
    GP.AddArc(fillGap(Rtop, Rleft, true, true), 0, 360);
    GP.AddArc(fillGap(Rtop, Rright, true, false), 0, 360);
    GP.AddArc(fillGap(Rbottom, Rleft, false, true), 0, 360);
    GP.AddArc(fillGap(Rbottom, Rright, false, false), 0, 360);

    panel1.Invalidate();
}

private void panel1_Paint(object sender, PaintEventArgs e)
{
    using (Pen pen = new Pen(Color.Black, 1.5f))
    {
        e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
        e.Graphics.DrawPath(pen, GP);
        if(checkBox1.Checked) e.Graphics.FillPath(Brushes.Red, GP);
    }
}

代码现在假定您的间隙不会比矩形更宽。
轮廓线的笔宽不应小于1.5f,否则填充将重叠太多。
此外,平滑模式应该是高质量的,这样就不会丢失任何像素。
以下是其外观:绘制和填充: drawnfilled

我该如何处理其他的角落呢?编辑:是的,我复制了代码,圆圈很大,大约是矩形的5倍大小。 - user1763295
我已经再次纠正了代码;明天我会添加其他的角落 - 我们正在经历一场热浪,这让我感到不适。 - TaW
是的,您不能将高度或宽度设置为0的形状;由于rex1和rex2位于相同的y位置(272),因此间隙为零。对于这些情况,您实际上不需要整个填充间隙,对吧?您将不得不检查rGap.Height * rGap.Width!= 0并跳过填充例程! - TaW
好的,我修复了这个问题,但是只有在你向上移动并开始向右移动时才有效,否则它会在错误的一侧绘制。例如:当它向下移动并向右转时,它会在内角而不是外角绘制。 - user1763295
让我们在聊天中继续这个讨论 - user1763295
显示剩余4条评论

2
除非空间是正方形,否则不能在空间中画圆。但您可以画一个椭圆。
您需要做的是:
1. 确定所讨论的矩形的范围。中心点是两个矩形相交的点(您想要填充的空白空间的右下部分)。左侧矩形的X坐标和顶部矩形的Y坐标为左上角。宽度将是2 *(center.X-left),高度将是2 *(center.Y-top)。 2. 在该矩形中填充椭圆
请注意,以上操作将绘制左上角的曲线部分。它不会完全填充下面的重叠矩形。
如果您想去除线条,请在重叠的空间中绘制没有边框的填充矩形(实际上,边框颜色与填充颜色相同)。然后按上述方法再次绘制填充椭圆,同样没有边框。
要绘制椭圆的边框,请查看DrawArc

看到帖子更新了,我似乎把它搞砸了。谢谢回复。 - user1763295
1
@user1763295:我的错误。我相信你想要中心点在两个矩形相遇的地方,并使其大小加倍。在那里画椭圆。我会更新我的答案。 - Jim Mischel
谢谢您的更新。我有点困惑如何计算中心? - user1763295
1
@user1763295:中心点是(topRectangle.left, leftRectangle.top) - Jim Mischel
我已经实现了这个功能,但只有当你在向右移动时才能正确绘制,而当你向上移动时无法正确绘制。 - user1763295
@user1763295:没错。将其推广到所有四个角落并不应该太难。 - Jim Mischel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接