钟摆受到影响但未绘制

本文关键字:绘制 受到影响 钟摆 | 更新日期: 2023-09-27 18:37:00

我目前的钟摆模拟有问题。
在我的程序中,您可以通过滑块选择要修改其值的摆锤,然后在单击更新按钮时将该摆锤更新为用户选择的属性。
还有一个默认按钮和零按钮,两者都修改该钟摆的值。长度在每个计时器刻度上都会更改,以便它普遍相同。
还有第二个滑块选择屏幕上显示的摆锤数量(1 到 5)。

问题是屏幕上看不到其他钟摆。

这是我的代码...
frmPendulm:

public partial class frmPendulum : Form
{
    private Timer timer;
    private List<Pendulum> pendulums;
    //all public static so they are actually global (can be used between classes and not just global to this class, mock flexibility).
    public static double angle = 0; //pendulums arm angle
    public static double aAcc = 0.00; //Angle acceleration
    public static double aVel = 0.00; //anglular velocity
    public static double damping = 0.000; //friction //friction
    public static double gravity = 0.0; //make gravity a constant
    public frmPendulum()
    {
        InitializeComponent();
        this.Shown += new EventHandler(frmPendulum_Shown);
        this.Paint += new PaintEventHandler(frmPendulum_Paint);
    }
    void frmPendulum_Shown(object sender, EventArgs e)
    {   
        //initialize the range for tbrPend
        tbrPend.Maximum = tbrNoOfPend.Value;
        pendulums = new List<Pendulum>(tbrNoOfPend.Maximum);
        for (int i = 0; i < tbrNoOfPend.Value; i++)
        {
            pendulums.Add(new Pendulum(this.Width + i * 40, this.Height, 0,0,0,0,0));
        }
        timer = new Timer() { Interval = 100 };
        timer.Tick += delegate(object s2, EventArgs e2)
        {
                this.SuspendLayout();
                this.Refresh();
                this.ResumeLayout();
                Pendulum.length = tbrLength.Value; //means length is changed on all pendulums
                updateValueVisuals();
        };
        timer.Start();
    }
    public void updateValueVisuals()
    {
        lblLength.Text= ("Length: " + Pendulum.length);
        lblAngle.Text = ("Angle: " + ((double)tbrAngle.Value) / 100.0);
        lblVel.Text = ("Vel: " + ((double)tbrAVel.Value) / 100.0);
        lblDamp.Text = ("Damping: " + ((double)tbrDamp.Value) / 100.0);
        lblGrav.Text = ("Gravity: " + ((double)tbrGrav.Value) / 100.0);
    }
    void frmPendulum_Paint(object sender, PaintEventArgs e)
    {
        foreach (Pendulum pendulum in pendulums)
        {
            pendulum.DrawPendulum(e.Graphics);
        }
    }

    private void btnDefault_Click(object sender, EventArgs e)
    {
        //sets values to a good calibration by default.
        Pendulum.length = 50;
        angle = Math.PI / 2; 
        aAcc = 0.00;           
        aVel = 0.00; 
        damping = 0.995; 
        gravity = 0.4; 
        UpdateSliders();
        effectSelectedPendulum(aAcc, aVel, damping, angle, gravity);
    }

    private void UpdateSliders()  
    {
        tbrLength.Value = Pendulum.length;
        tbrAngle.Value = (int)(angle * 100.0); 
        //tbrAAcc.Value = (int) Pendulum.aAcc; //Removed acceleration as it is re-calculated anyway.
        tbrAVel.Value = (int)(aVel* 100.0); 
        tbrDamp.Value = (int)(damping * 100.0); 
        tbrGrav.Value = (int)(gravity * 100.0);
    }
    private void btnUpdateValues_Click(object sender, EventArgs e)
    {
        /** The trackbars only use ilnteger values so to increment in decimals certain vaues have to be divided by 100 so they are correct in the simulation.
         * For example is I want the gravity to be 0.4 my track bars value will have to be 40 / 100 = 0.40 
         * Another example will be angle that will go from -3 to 3 incrementing in decimals we go from -300 to 300 /100 = 3 **/
        Pendulum.length = tbrLength.Value; //length is ok as it is an integer
        angle = ((double)tbrAngle.Value) / 100.0; //both numerator and denominator must be of the same type.
        // acceleration is calculated so isn't sent
        aVel = ((double)tbrAVel.Value) / 100.0;
        damping = ((double)tbrDamp.Value) / 100.0;
        gravity = ((double)tbrGrav.Value) / 100.0;
        effectSelectedPendulum(aAcc, aVel, damping, angle, gravity);
    }
    private void button1_Click(object sender, EventArgs e)
    {
        //zero's everything except length.
        Pendulum.length = 10; //can't be 0 must be 10
        angle = 0; 
        aAcc = 0.00; 
        aVel = 0.00; 
        damping = 0; 
        gravity = 0; 
        UpdateSliders();
        effectSelectedPendulum(aAcc, aVel, damping, angle, gravity);
    }

    private void effectSelectedPendulum(double aAcc, double aVel, double damping, double angle, double gravity)
    {
         int index = tbrPend.Value - 1;
         pendulums[index] = new Pendulum(Width + index * 40, ClientRectangle.Height, aAcc, aVel, damping, angle, gravity);
    }
    private void tbrNoOfPend_ValueChanged(object sender, EventArgs e)
    {
        tbrPend.Maximum = tbrNoOfPend.Value;
        if (tbrNoOfPend.Value < pendulums.Count)
        {
            pendulums.RemoveRange(tbrNoOfPend.Value, pendulums.Count - tbrNoOfPend.Value);
            return;
        }
        if (tbrNoOfPend.Value > pendulums.Count)
        {
            for (int i = pendulums.Count; i < tbrNoOfPend.Value; i++)
            {
                pendulums.Add(new Pendulum(this.Width + i * 40, this.ClientRectangle.Height, 0, 0, 0, 0, 0));
            }
        }
    }
}

摆锤类:

class Pendulum
{
    public static int length = 10;//length of arm /** can't be less than 0 or will break.
    int originX = 0;
    int originY = 0; //allways 0
    int bobX; // = frmWidth / 2;
    int bobY; // = (int)length; Drawn in pendulm as don't really need to be global. Are currently for flexibilty.
    //public static int returnvalue;
    Timer timer; //global for flexibility
    public Pendulum(int frmWidth, int frmHeight, double aAcc, double aVel, double damping, double angle, double gravity)  
    {
        timer = new Timer() { Interval = 30 };
        originX = frmWidth / 2;
        timer.Tick += delegate(object sender, EventArgs e)
        {
            //-----------------drawing variables------------------------------//
            originY = 0;
            //to be relative to origin we go:
            bobX = originX + (int)(Math.Sin(angle) * length);
            bobY = originY + (int)(Math.Cos(angle) * length);
            //gravity
            aAcc = (-1 * gravity / length) * Math.Sin(angle); //calculate acceleration
            aVel += aAcc;//increment velcocity
            angle += aVel;//incrment angle
            aVel *= damping;//friction action, pendulum eventually 0's

        };
        //returnvalue = string.Format("{0}Length:" + length + ",{0} Angle: " + angle + ",{0}Vel: " + aVel + ",{0}Damping: " + damping + ",{0}Gravity: " + gravity, Environment.NewLine);
        timer.Start();
    }
    public void DrawPendulum(Graphics g) 
    {
        g.DrawLine(Pens.Red, originX, originY, bobX, bobY);
            g.FillEllipse(Brushes.Black, bobX - 8 , bobY, 20, 20); //-8 to make it look more central!
    }
}

钟摆受到影响但未绘制

不要在一开始就创建所有的钟摆。创建的摆锤数和tbrPend滑块的最大值应受tbrNoOfPend滑块的实际值的影响。

我建议使用List<Pendulum>并摆脱p1 p5变量。

private List<Pendulum> pendulums;
void frmPendulum_Shown(object sender, EventArgs e)
{
    // initialize the range for tbrPend
    tbrPend.Maximum = tbrNoOfPend.Value;
    pendulums = new List<Pendulum>(tbrNoOfPend.Maximum);
    for (int i = 0; i < tbrNoOfPend.Value; i++)
    {
        pendulums.Add(new Pendulum(this.Width + i * 40, this.ClientRectangle.Height, 0, 0, 0, 0, 0));
    }
    timer = new Timer()
    {
        Interval = 100
    };
    timer.Tick += delegate(object s2, EventArgs e2)
    {
        this.SuspendLayout();
        this.Refresh();
        this.ResumeLayout();
        Pendulum.length = tbrLength.Value; //means length is changed on all pendulums
        updateValueVisuals();
    };
    timer.Start();
}

现在,Paint事件处理程序和effectSelectedPendulum方法变得更好了:

void frmPendulum_Paint(object sender, PaintEventArgs e)
{
    foreach (Pendulum pendulum in pendulums)
    {
        pendulum.DrawPendulum(e.Graphics);
    }
}
private void effectSelectedPendulum(double aAcc, double aVel, double damping, double angle, double gravity)
{
    int index = tbrPend.Value - 1;
    pendulums[index] = new Pendulum(Width + index * 40, ClientRectangle.Height, aAcc, aVel, damping, angle, gravity);
}

您唯一需要添加的是tbrNoOfPend滑块的ValueChanged事件的处理程序。在这里,您可以更新tbrPend滑块的最大值,并分别创建或删除钟摆:

private void tbrNoOfPend_ValueChanged(object sender, EventArgs e)
{
    tbrPend.Maximum = tbrNoOfPend.Value;
    if (tbrNoOfPend.Value < pendulums.Count)
    {
        pendulums.RemoveRange(tbrNoOfPend.Value, pendulums.Count - tbrNoOfPend.Value);
        return;
    }
    if (tbrNoOfPend.Value > pendulums.Count)
    {
        for (int i = pendulums.Count; i < tbrNoOfPend.Value; i++)
        {
            pendulums.Add(new Pendulum(this.Width + i * 40, this.ClientRectangle.Height, 0, 0, 0, 0, 0));
        }
    }
}