2013-10-26 2 views
0

У меня проблема с моделями Pendulum.
В моей программе вы выбираете маятник, который хотите изменить значения с помощью слайдера, а затем обновите этот маятник до выбранных вами свойств по щелчку кнопки обновления.
Существует также кнопка по умолчанию и нуль, изменяющая значения для этого маятника. Длина изменяется на каждый таймер так, чтобы он был одинаковым.
Существует также второй слайдер, определяющий, сколько маятников (от 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)); 
      } 
     } 
    } 

} 

Pendulum Класс:

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! 
    } 
} 

ответ

0

Не создавать все маятники в самом начале. Количество созданных маятников и максимальное значение для ползунка 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); 
} 

Единственное, что вы должны добавить в обработчик в ValueChanged случае tbrNoOfPend слайдера. Там вы обновляете максимум tbrPend слайдера и создать или удалить pendulumns соответственно:

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)); 
     } 
    } 
} 
+0

Я смотрел на это решение, и после разговора с другими людьми, об этом я думаю, что вы не правы, не будет принимать до I Однако он попытался. –

+0

Я запустил этот код через свою программу, но по какой-то причине теперь я не вижу нескольких маятников. Я обновляю свой ответ с помощью своего нового кода, поскольку я не могу понять, что не так ... вся логика кажется мне верной. –

+0

@CoreyFord Я пережил то же самое после копирования вашего обновленного кода. Первоначально значение 'tbrLength.Value' было установлено равным 0, которое, в свою очередь, обновляло' Pendulum.length' до 0. Поэтому вычисление маятников постоянно бросало исключения. – pescolino