在2个点之间绘制一个具有指定"胖度"的椭圆

use*_*910 0 c# graphics gdi

我有一个C#位图对象,我能够从A点到B点画一条线.

我在图的边缘有2个点,我想绘制一个从A到B的椭圆.基本的g.DrawEllipse()只能完美地水平或垂直绘制椭圆,但是我需要椭圆是一种从图像的一端到另一端的对角线.

My bitmap:    200 tall by 500 wide
Point A:      Column 0, Row 20   (0,20)
Point B:      Column 499, Row 60 (499, 60)
Widest Point: 30  - Narrow Radius of the ellipse
Run Code Online (Sandbox Code Playgroud)

这是我到目前为止,绘制椭圆没有我需要的重载,所以请帮助那里:

    using (Graphics g = Graphics.FromImage(bmp))
    {
        g.DrawLine(pen, new Point(20,0), new Point(499,60));
        g.DrawEllipse(pen, 20, 0, someWidth, someHeight);
    }
Run Code Online (Sandbox Code Playgroud)

TaW*_*TaW 7

以下是如何使用DrawEllipse旋转方法,短轴和两个顶点.

首先我们计算Size边界Rectangle:

考虑到Points A and B坐在短边的长度,smallSize我们得到了一个小的毕达哥拉斯的长边:

int longSide = (int)(Math.Sqrt((A.Y - B.Y) * (A.Y - B.Y) + (B.X - A.X) * (B.X - A.X)));
Run Code Online (Sandbox Code Playgroud)

所以:

Size size = new System.Drawing.Size(longSide, smallSize);
Run Code Online (Sandbox Code Playgroud)

接下来我们需要旋转角度:

float angle = -(float)(Math.Atan2(A.Y - B.Y, B.X - A.X) * 180f / Math.PI);
Run Code Online (Sandbox Code Playgroud)

并且它将使得更容易获得中心Point C:

Point C = new Point((A.X + B.X)/ 2, (A.Y + B.Y)/ 2);
Run Code Online (Sandbox Code Playgroud)

我们想要的最后一件事就是绘制一个给定椭圆的例程,以一定角度Size旋转C:

void DrawEllipse(Graphics G, Pen pen, Point center, Size size, float angle)
{
    int h2 = size.Height / 2;
    int w2 = size.Width / 2;
    Rectangle rect = new Rectangle( new Point(center.X - w2, center.Y - h2), size );

    G.TranslateTransform(center.X, center.Y);
    G.RotateTransform(angle);
    G.TranslateTransform(-center.X, -center.Y);
    G.DrawEllipse(pen, rect);
    G.ResetTransform();
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

这是一个小小的测试平台,将所有这些结合在一起:

Point A = new Point(200, 200); // *
Point B = new Point(500, 250);
int smallSize = 50;


void doTheDraw(PictureBox pb)
{
    Bitmap bmp = new Bitmap(pb.Width, pb.Height);

    float angle = -(float)(Math.Atan2(A.Y - B.Y, B.X - A.X) * 180f / Math.PI);
    int longSide = (int)(Math.Sqrt((A.Y - B.Y) * (A.Y - B.Y) + (B.X - A.X) * (B.X - A.X)));
    Point C = new Point((A.X + B.X) / 2, (A.Y + B.Y) / 2);
    Size size = new System.Drawing.Size((int)longSide, smallSize);

    using (Pen pen = new Pen(Color.Orange, 3f))
    using (Graphics g = Graphics.FromImage(bmp))
    {
        // a nice background grid (optional):
        DrawGrid(g, 0, 0, 100, 50, 10,
            Color.LightSlateGray, Color.DarkGray, Color.Gainsboro);

        // show the points we use (optional):
        g.FillEllipse(Brushes.Red, A.X - 4, A.Y - 4, 8, 8);
        g.FillRectangle(Brushes.Red, B.X - 3, B.Y - 3, 7, 7);
        g.FillEllipse(Brushes.Red, C.X - 5, C.Y - 5, 11, 11);

        // show the connection line (optional):
        g.DrawLine(Pens.Orange, A, B);

        // here comes the ellipse:
        DrawEllipse(g, pen, C, size, angle);
    }
    pb.Image = bmp;
}
Run Code Online (Sandbox Code Playgroud)

网格是一个很好的帮手:

void DrawGrid(Graphics G, int ox, int oy, 
              int major, int medium, int minor, Color c1, Color c2, Color c3)
{
    using (Pen pen1 = new Pen(c1, 1f))
    using (Pen pen2 = new Pen(c2, 1f))
    using (Pen pen3 = new Pen(c3, 1f))
    {
        pen2.DashStyle = DashStyle.Dash;
        pen3.DashStyle = DashStyle.Dot;
        for (int x = ox; x < G.VisibleClipBounds.Width; x += major)
            G.DrawLine(pen1, x, 0, x, G.VisibleClipBounds.Height);
        for (int y = oy; y < G.VisibleClipBounds.Height; y += major)
            G.DrawLine(pen1, 0, y, G.VisibleClipBounds.Width, y);

        for (int x = ox; x < G.VisibleClipBounds.Width; x += medium)
            G.DrawLine(pen2, x, 0, x, G.VisibleClipBounds.Height);
        for (int y = oy; y < G.VisibleClipBounds.Height; y += medium)
            G.DrawLine(pen2, 0, y, G.VisibleClipBounds.Width, y); 

        for (int x = ox; x < G.VisibleClipBounds.Width; x += minor)
            G.DrawLine(pen3, x, 0, x, G.VisibleClipBounds.Height);
        for (int y = oy; y < G.VisibleClipBounds.Height; y += minor)
            G.DrawLine(pen3, 0, y, G.VisibleClipBounds.Width, y);
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,我创建了 A, B, smallSide类级变量,因此我可以在测试期间修改它们(我做了*)...

正如你所看到的,我已经添加了一个TrackBar来制作smallside动态; 为了更有趣,我添加了这个MouseClick活动:

private void pictureBox1_MouseClick(object sender, MouseEventArgs e)
{
    if (e.Button.HasFlag(MouseButtons.Left)) A = e.Location;
    else B = e.Location;
    doTheDraw(pictureBox1);
}
Run Code Online (Sandbox Code Playgroud)

请注意,我不在乎处理旧的Bitmap; 你当然应该..!