简体   繁体   English

填充两个矩形之间的空间

[英]Filling the space between two rectangles

how would I go about filling the space between two rectangles when they are not vertically aligned. 当它们没有垂直对齐时,我将如何填充两个矩形之间的空间。 So if one rectangle moves up the gap between it and the next rectangle (In a chain which all follow the same path) looks smooth. 因此,如果一个矩形向上移动,它与下一个矩形之间的间隙(在一条链中,它们都遵循相同的路径)看起来很平滑。

Example: 例:

Current: 当前: 丑陋的差距

Desired: 期望: 期望的样子

My current drawing code: 我目前的绘图代码:

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);
}

Underlying draw: 标的平局:

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);

Edit: 编辑:

After following Jim and commenter's advice, I came up with the following. 在听完Jim和评论者的建议之后,我提出了以下建议。 The maths seems to be wrong and it doesn't really get the effect I wanted at all though. 数学似乎是错误的,但它并没有真正得到我想要的效果。

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);

在此输入图像描述

Edit 2: Been following everyone's advice and editing as I go along. 编辑2:跟随每个人的建议和编辑。 Jim's works now but it only draws at all if you are moving up and you start moving right. 吉姆现在的作品,但如果你向上移动并且你开始向右移动它只会吸引人。

And now with TAW's advice I get ArguementInvalid, I assume this is because the rGap rectangle's height is 0. 现在有了TAW的建议,我得到了ArguementInvalid,我认为这是因为rGap矩形的高度为0。

My implementation of TAW's: 我对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);

Edit 3: I have developed my own solution after studying the problem a little more, it's not the solution I wanted but hopefully it should help someone else. 编辑3:在研究了问题之后我已经开发了自己的解决方案,这不是我想要的解决方案,但希望它能帮助别人。 Now it just needs converting to rounded corners. 现在它只需要转换为圆角。

Code: 码:

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);

Produces: 生产: 在此输入图像描述

You can't necessarily draw a circle in the space unless the space is square. 除非空间是正方形,否则您不一定在空间中绘制圆。 But you can draw an ellipse. 但你可以绘制一个椭圆。

What you need to do: 你需要做什么:

  1. Determine extents of the rectangle in question. 确定有问题的矩形的范围。 The center point is the point where the two rectangles meet (the bottom right part of the blank space you want to fill. The top left is the X coordinate of the left rectangle and the Y coordinate of the top rectangle. The width would be 2*(center.X - left) and the height would be 2*(center.Y - top) . 中心点是两个矩形相交的点(要填充的空白区域的右下角部分。左上角是左边矩形的X坐标和顶部矩形的y坐标。宽度为2*(center.X - left) ,高度为2*(center.Y - top)
  2. Fill an ellipse in that rectangle. 在该矩形中填充椭圆

Note that the above will have the effect of drawing the top-left curved portion. 注意,上述将具有绘制左上弯曲部分的效果。 It won't fully fill the overlapping rectangle below. 它不会完全填充下面的重叠矩形。

If you want to get rid of the lines, draw a filled rectangle without a border (actually, with the border the same color as the fill color) in the overlapping space. 如果要删除线条,请在重叠空间中绘制一个没有边框的填充矩形(实际上,边框与填充颜色的颜色相同)。 Then draw the filled ellipse as described above, again without a border. 然后如上所述绘制填充的椭圆,再次没有边框。

To draw the border of the ellipse, look into DrawArc . 要绘制椭圆的边框,请查看DrawArc

Here is a solution that draws all four rounded corneres for four rectangles. 这是一个解决方案,绘制四个矩形的所有四个圆角。

I create four rectangles overlapping with various gaps and add them and the arcs to fill the gaps to a GraphicsPath. 我创建了四个与各种间隙重叠的矩形,并添加它们和弧形以填充到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);
    }
}

The code now assumes that your gaps are not wider than the rectanlges. 现在代码假设您的间隙不比矩形宽。

The Pen for the outline should not be smaller that 1.5f or the filling will overlap too much. 轮廓的笔不应小于1.5f或填充将重叠太多。

Also the Smoothing mode should be high quality, so no pixels get lost. 平滑模式也应该是高质量的,因此不会丢失像素。

Here is how it looks : Drawn & filled: 以下是它的外观:绘制和填充:

画填充

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM