画出经过 3 个点的椭圆

Posted

技术标签:

【中文标题】画出经过 3 个点的椭圆【英文标题】:Draw ellipse passing through 3 points 【发布时间】:2018-05-05 02:58:08 【问题描述】:

我有下一个任务 - 通过 3 个点绘制椭圆(如图所示)。 . 用户可以拖动这些点来改变椭圆的大小。放置在大轴边缘的两个点。在我的解决方案中,我通过 Graphics 类使用 GDI。 现在我的解决方案是计算对应于椭圆的矩形并使用 DrawEllipse 方法和旋转变换(如果需要)。但是这个解决方案有很多数学计算。也许有最简单的方法来解决这个任务?

【问题讨论】:

【参考方案1】:

这里是如何从一个旋转、短轴和两个顶点使用DrawEllipse方法。

首先我们计算边界RectangleSize

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

所以:

Size size = new System.Drawing.Size(longSide, smallSize);

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

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

而且它会让事情变得更容易获得中心Point C

Point C = new Point((A.X + B.X)/ 2, (A.Y + B.Y)/ 2);

我们最不想要的就是绘制一个给定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();

[![在此处输入图片描述][1]][1]

这里有一个小测试平台,将所有内容结合在一起:

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;

网格是个好帮手:

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

请注意,我创建了 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);

我希望我的一些逻辑可以帮助您了解您想要实现的目标。您提出的下一个问题尝试添加更多信息并减少通用性。

【讨论】:

谢谢!有些事情现在对我来说并不完全清楚,但我想我可以解决它。现在我只需要计算小尺寸,这比我最初的想法要好得多。 我发现了一个错误。角度应该没有减号以正确绘图。还需要为点的可用坐标添加条件。【参考方案2】:

计算将前两个点带到(-a, 0)(a, 0) 的相似变换(平移和旋转)。 [这可以通过矩阵变换或复数来完成。]

对第三个点应用相同的变换。现在简化椭圆的方程为

x² / a² + y² / b² = 1.

您只需通过插入第三个点的简化坐标来确定参数b

b = y / √(1 - x²/a²).

现在你有

中心, 轴的方向, 长轴的长度, 短轴的长度。

【讨论】:

以上是关于画出经过 3 个点的椭圆的主要内容,如果未能解决你的问题,请参考以下文章

如何用 css 画出一个椭圆

椭圆曲线算法:简单介绍

Matlab&Mathematica对三维空间上的点进行椭圆拟合

椭圆曲线算法的基本原理及实现

星月图标制作

在c ++中查找包含一组点的最小面积椭圆