画过3个点的椭圆
Draw ellipse passing through 3 points
我有下一个任务 - 通过 3 个点绘制椭圆槽(如图所示)。
.
用户可以拖动这些点来改变椭圆的大小。放置在大轴边缘的两个点。在我的解决方案中,我通过 Graphics class 使用 GDI。
现在我的解决方案是计算对应于椭圆的矩形并使用
DrawEllipse 方法和旋转变换(如果需要)。但是这个解有很多数学计算。也许有解决此任务的最简单方法?
这里是如何从旋转、短轴和两个顶点使用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)));
所以 :
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
class 级变量,以便我可以在测试期间修改它们,(我做了 *
)..
如您所见,我添加了一个 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);
}
我希望我的一些逻辑可以帮助您实现您想要实现的目标。您提出的下一个问题尝试添加更多信息并减少通用性。
计算将前两个点带到 (-a, 0)
和 (a, 0)
的相似变换(平移和旋转)。 [这可以通过矩阵变换或复数来完成。]
对第三个点应用相同的变换。现在缩小椭圆的方程是
x² / a² + y² / b² = 1.
您只需通过插入第三个点的简化坐标来确定参数b
,
b = y / √(1 - x²/a²).
现在你有
- 中心,
- 轴的方向,
- 长轴的长度,
- 短轴的长度。
我有下一个任务 - 通过 3 个点绘制椭圆槽(如图所示)。
用户可以拖动这些点来改变椭圆的大小。放置在大轴边缘的两个点。在我的解决方案中,我通过 Graphics class 使用 GDI。
现在我的解决方案是计算对应于椭圆的矩形并使用
DrawEllipse 方法和旋转变换(如果需要)。但是这个解有很多数学计算。也许有解决此任务的最简单方法?
这里是如何从旋转、短轴和两个顶点使用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)));
所以 :
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
class 级变量,以便我可以在测试期间修改它们,(我做了 *
)..
如您所见,我添加了一个 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);
}
我希望我的一些逻辑可以帮助您实现您想要实现的目标。您提出的下一个问题尝试添加更多信息并减少通用性。
计算将前两个点带到 (-a, 0)
和 (a, 0)
的相似变换(平移和旋转)。 [这可以通过矩阵变换或复数来完成。]
对第三个点应用相同的变换。现在缩小椭圆的方程是
x² / a² + y² / b² = 1.
您只需通过插入第三个点的简化坐标来确定参数b
,
b = y / √(1 - x²/a²).
现在你有
- 中心,
- 轴的方向,
- 长轴的长度,
- 短轴的长度。