【问题标题】:Transcribing a polygon on a circle在圆上转录多边形
【发布时间】:2013-10-06 15:35:09
【问题描述】:

我目前正在尝试在一个圆圈内刻一个十边形的对角线

喜欢这个

在 c# 中,我的方法是创建一个圆圈

e.Graphics.DrawEllipse(myPen, 0, 0, 100, 100);

在里面画线

 e.Graphics.DrawLine(myPen, 20, 5, 50, 50);

之后我会画一个十边形的多边形。

目前我坚持如何将圆分成 10 个部分/找到圆圆周上点的正确坐标,因为我数学不好, 我想知道我如何知道圆的圆周中的下一个点,我的圆的大小如上所示。
而且我还想为我的问题提出更好的方法。

谢谢你:)

【问题讨论】:

  • 查找一些三角函数。由于您知道您使用的是 36、72、108... 度,并且您知道您的半径 R,因此您可以使用 Math.SinMath.Cos 来计算每个点的 X/Y 坐标。 mathwords.com/s/sohcahtoa.htm 编辑:例如,第一个点在 36 度处的 x 坐标可能是 Radius * Math.Cos(Math.PI / 5)(请注意,Math.Sin/Cos 采用弧度,而不是度数)

标签: c# winforms algorithm math


【解决方案1】:

仅针对粗粒和小腿,这是一个通用实现,它将在您传递的 Rectangle 中写入一个 X 边多边形。请注意,在这种方法中,我实际上并没有计算任何绝对点。相反,我正在平移原点,旋转表面,并使用固定长度和角度仅相对于原点绘制线条。这在循环中重复以达到下面的最终结果,并且非常类似于在Logo中指挥海龟:

public partial class Form1 : Form
{

    PictureBox pb = new PictureBox();
    NumericUpDown nud = new NumericUpDown();

    public Form1()
    {
        InitializeComponent();

        this.Text = "Inscribed Polygon Demo";

        TableLayoutPanel tlp = new TableLayoutPanel();
        tlp.RowCount = 2;
        tlp.RowStyles.Clear();
        tlp.RowStyles.Add(new RowStyle(SizeType.AutoSize));
        tlp.RowStyles.Add(new RowStyle(SizeType.Percent, 100));
        tlp.ColumnCount = 2;
        tlp.ColumnStyles.Clear();
        tlp.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
        tlp.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
        tlp.Dock = DockStyle.Fill;
        this.Controls.Add(tlp);

        Label lbl = new Label();
        lbl.Text = "Number of Sides:";
        lbl.TextAlign = ContentAlignment.MiddleRight;
        tlp.Controls.Add(lbl, 0, 0);

        nud.Minimum = 3;
        nud.Maximum = 20;
        nud.AutoSize = true;
        nud.ValueChanged += new EventHandler(nud_ValueChanged);
        tlp.Controls.Add(nud, 1, 0);

        pb.Dock = DockStyle.Fill;
        pb.Paint += new PaintEventHandler(pb_Paint);
        pb.SizeChanged += new EventHandler(pb_SizeChanged);
        tlp.SetColumnSpan(pb, 2);
        tlp.Controls.Add(pb, 0, 1);
    }

    void nud_ValueChanged(object sender, EventArgs e)
    {
        pb.Refresh();
    }

    void pb_SizeChanged(object sender, EventArgs e)
    {
        pb.Refresh();
    }

    void pb_Paint(object sender, PaintEventArgs e)
    {
        // make circle centered and 90% of PictureBox size:
        int Radius = (int)((double)Math.Min(pb.ClientRectangle.Width, pb.ClientRectangle.Height) / (double)2.0 * (double).9);
        Point Center = new Point((int)((double)pb.ClientRectangle.Width / (double)2.0), (int)((double)pb.ClientRectangle.Height / (double)2.0));
        Rectangle rc = new Rectangle(Center, new Size(1, 1));
        rc.Inflate(Radius, Radius);

        InscribePolygon(e.Graphics, rc, (int)nud.Value);
    }

    private void InscribePolygon(Graphics G, Rectangle rc, int numSides)
    {
        if (numSides < 3)
            throw new Exception("Number of sides must be greater than or equal to 3!");

        float Radius = (float)((double)Math.Min(rc.Width, rc.Height) / 2.0);
        PointF Center = new PointF((float)(rc.Location.X + rc.Width / 2.0), (float)(rc.Location.Y + rc.Height / 2.0));
        RectangleF rcF = new RectangleF(Center, new SizeF(1, 1));
        rcF.Inflate(Radius, Radius);
        G.DrawEllipse(Pens.Black, rcF);

        float Sides = (float)numSides;
        float ExteriorAngle = (float)360 / Sides;
        float InteriorAngle = (Sides - (float)2) / Sides * (float)180;
        float SideLength = (float)2 * Radius * (float)Math.Sin(Math.PI / (double)Sides);
        for (int i = 1; i <= Sides; i++)
        {
            G.ResetTransform();
            G.TranslateTransform(Center.X, Center.Y);
            G.RotateTransform((i - 1) * ExteriorAngle);
            G.DrawLine(Pens.Black, new PointF(0, 0), new PointF(0, -Radius));
            G.TranslateTransform(0, -Radius);
            G.RotateTransform(180 - InteriorAngle / 2);
            G.DrawLine(Pens.Black, new PointF(0, 0), new PointF(0, -SideLength));
        }
    }

}

我在Regular Polygon Calculator 得到了边长的公式。

【讨论】:

  • 这是一个很好的例子。
  • 如果我要使用这种方法,我怎样才能将整个对象(Dacagon inscided in a circle)从一个点移动到另一个点?我项目的主要目标是项目翻译、旋转等。
  • 它根据你传入的 Rectangle 进行绘制。只需将新的 Rectangle 传递给 InscribePolygon(),它就会在指定的位置绘制它。
  • 在类(表单)级别存储矩形。然后您只需更改该矩形并调用this.Refresh();。然后 Paint() 事件将简单地将 e.Graphics、矩形和边数 (10) 传递给 InscribePolygon()。十边形将立即以新的大小/位置重绘。
【解决方案2】:

解决此问题的一种方法是使用三角函数sincos。在一个循环中以弧度为单位向它们传递所需的角度(您需要 2*π/10 的倍数,即 a = i*π/5 用于 i 介于 0 和 9 之间,包括 0 和 9)。 R*sin(a) 将为您提供与原点的垂直偏移; R*cos(a) 会给你水平偏移量。

请注意,sincos 的范围是从 -11,因此您会看到正面和负面的结果。您需要为圆心添加偏移量,以使这些点出现在正确的位置。

生成点列表后,将点 i 连接到点 i+1。当你到达第九个点时,将它连接到初始点以完成多边形。

【讨论】:

    【解决方案3】:

    我没有测试它,但我认为它是可以的。

    #define DegreeToRadian(d)  d * (Pi / 180)
    
    float r = 1; // radius
    float cX = 0; // centerX
    float cY = 0; // centerY
    int numSegment = 10;
    float angleOffset = 360.0 / numSegment;
    float currentAngle = 0;
    for (int i = 0; i < numSegment; i++)
    {
        float startAngle = DegreeToRadian(currentAngle);
        float endAngle = DegreeToRadian(fmod(currentAngle + angleOffset, 360));
    
        float x1 = r * cos(startAngle) + cX;
        float y1 = r * sin(startAngle) + cY;
        float x2 = r * cos(endAngle) + cX;
        float y2 = r * sin(endAngle) + cY;
    
        currentAngle += angleOffset;
    
        // [cX, cY][x1, y1][x2, y2]
    }
    

    (fmod是c++函数等于floatNumber % floatNumber)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-06-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-05
      • 2018-07-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多