1

I'm attempting to create an animation that will help me visualize how different brain regions signal to each other. As an example, brain region 1 (for now visualized as a text box) blinks and this triggers a trail of lights to brain region 2 which blinks and triggers a 2nd signal etc etc..

To that end I've tried to write up a small traffic light code in MS visual studio C# similar to what many others have done before me:

private void timer1_Tick(object sender, EventArgs e)
{

    if (ovalshape1.visible == true)
    {
        ovalshape1.visible = false;
        ovalshape2.visible = true;
     }
     else if (ovalshape2.visible == true)
     {
         ovalshape1.visible = true;
         ovalshape2.visible = false;
     }
}

This code works well also if I expand to e.g. 5 "lights" as long as only one "light" is on at a time. In order to produce the trailing effect, I would like to have several lights on at one time and this is where I'm running into problems as this seems to confuse my IF setup...

The trailing light would look something this:

Trailing lights

I've tried to bypass this by producing a boolean array to control which lights are on and off, as I thought that would greatly shorten the amount of code that I would need to write, but my coding abilities are not up to that.

I've also tried implementing a loop, thinking that in this way I could just define which lights are on/off when i=0, i=1 and so on... but is that even done inside a timer?

I've tried reading up on how to approach this problem, but have not been able to find anything that seemed directly applicable to my situation. I hope that you can help me.

Ultimately I would like to show signaling between 7 brain regions.

Something like

Region1 --> R2 --> R3 --> R4 --> R5 <--R6

Region7 recieves input from R5.

I envision signaling between the individual regions as collection of dots that turn on/off in a trailing pattern similar to what is achieved using traffic light code.

To complicate matters, I would like to run two animations in parallel, depicting "normal" signaling in the brain and what I hypothesize is (part of) the pathological signaling in schizophrenia.

So far I've managed to create two parallel rows of 5 trailing lights. Each row is controlled by a timer, which allows me to adjust the speed for each row.

I can scale this so that each timer controls multiple trailing lights using the code below:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    int counter = 0;
    string shapeColorON = "White";
    string shapeColorOFF = "Black";

    private void buttonStart_Click(object sender, EventArgs e)
    {
        timer1.Start();
    }

    private void timer1_Tick(object sender, EventArgs e)
    {
        counter++;

        if (counter == 1)
        {

            ovalShape1.FillColor = Color.FromName(shapeColorON);
            ovalShape2.FillColor = Color.FromName(shapeColorOFF);
            ovalShape3.FillColor = Color.FromName(shapeColorOFF);
            ovalShape4.FillColor = Color.FromName(shapeColorOFF);
            ovalShape5.FillColor = Color.FromName(shapeColorOFF);
            ovalShape6.FillColor = Color.FromName(shapeColorON);
            ovalShape7.FillColor = Color.FromName(shapeColorOFF);
            ovalShape8.FillColor = Color.FromName(shapeColorOFF);
            ovalShape9.FillColor = Color.FromName(shapeColorOFF);
            ovalShape10.FillColor = Color.FromName(shapeColorOFF);
            ovalShape11.FillColor = Color.FromName(shapeColorON);
            ovalShape12.FillColor = Color.FromName(shapeColorOFF);
            ovalShape13.FillColor = Color.FromName(shapeColorOFF);
            ovalShape14.FillColor = Color.FromName(shapeColorOFF);
            ovalShape15.FillColor = Color.FromName(shapeColorOFF);
            ovalShape16.FillColor = Color.FromName(shapeColorON);
            ovalShape17.FillColor = Color.FromName(shapeColorOFF);
            ovalShape18.FillColor = Color.FromName(shapeColorOFF);
            ovalShape19.FillColor = Color.FromName(shapeColorOFF);
            ovalShape20.FillColor = Color.FromName(shapeColorOFF);
            ovalShape21.FillColor = Color.FromName(shapeColorON);
            ovalShape22.FillColor = Color.FromName(shapeColorOFF);
            ovalShape23.FillColor = Color.FromName(shapeColorOFF);
            ovalShape24.FillColor = Color.FromName(shapeColorOFF);
            ovalShape25.FillColor = Color.FromName(shapeColorOFF);

    }
    else if (counter == 2)
        {


            ovalShape1.FillColor = Color.FromName(shapeColorON);
            ovalShape2.FillColor = Color.FromName(shapeColorON);
            ovalShape3.FillColor = Color.FromName(shapeColorOFF);
            ovalShape4.FillColor = Color.FromName(shapeColorOFF);
            ovalShape5.FillColor = Color.FromName(shapeColorOFF);
            ovalShape6.FillColor = Color.FromName(shapeColorON);
            ovalShape7.FillColor = Color.FromName(shapeColorON);
            ovalShape8.FillColor = Color.FromName(shapeColorOFF);
            ovalShape9.FillColor = Color.FromName(shapeColorOFF);
            ovalShape10.FillColor = Color.FromName(shapeColorOFF);
            ovalShape11.FillColor = Color.FromName(shapeColorON);
            ovalShape12.FillColor = Color.FromName(shapeColorON);
            ovalShape13.FillColor = Color.FromName(shapeColorOFF);
            ovalShape14.FillColor = Color.FromName(shapeColorOFF);
            ovalShape15.FillColor = Color.FromName(shapeColorOFF);
            ovalShape16.FillColor = Color.FromName(shapeColorON);
            ovalShape17.FillColor = Color.FromName(shapeColorON);
            ovalShape18.FillColor = Color.FromName(shapeColorOFF);
            ovalShape19.FillColor = Color.FromName(shapeColorOFF);
            ovalShape20.FillColor = Color.FromName(shapeColorOFF);
            ovalShape21.FillColor = Color.FromName(shapeColorON);
            ovalShape22.FillColor = Color.FromName(shapeColorON);
            ovalShape23.FillColor = Color.FromName(shapeColorOFF);
            ovalShape24.FillColor = Color.FromName(shapeColorOFF);
            ovalShape25.FillColor = Color.FromName(shapeColorOFF);
    }
        else if (counter == 3)
        {

            ovalShape1.FillColor = Color.FromName(shapeColorOFF);
            ovalShape2.FillColor = Color.FromName(shapeColorON);
            ovalShape3.FillColor = Color.FromName(shapeColorON);
            ovalShape4.FillColor = Color.FromName(shapeColorOFF);
            ovalShape5.FillColor = Color.FromName(shapeColorOFF);
            ovalShape6.FillColor = Color.FromName(shapeColorOFF);
            ovalShape7.FillColor = Color.FromName(shapeColorON);
            ovalShape8.FillColor = Color.FromName(shapeColorON);
            ovalShape9.FillColor = Color.FromName(shapeColorOFF);
            ovalShape10.FillColor = Color.FromName(shapeColorOFF);
            ovalShape11.FillColor = Color.FromName(shapeColorOFF);
            ovalShape12.FillColor = Color.FromName(shapeColorON);
            ovalShape13.FillColor = Color.FromName(shapeColorON);
            ovalShape14.FillColor = Color.FromName(shapeColorOFF);
            ovalShape15.FillColor = Color.FromName(shapeColorOFF);
            ovalShape16.FillColor = Color.FromName(shapeColorOFF);
            ovalShape17.FillColor = Color.FromName(shapeColorON);
            ovalShape18.FillColor = Color.FromName(shapeColorON);
            ovalShape19.FillColor = Color.FromName(shapeColorOFF);
            ovalShape20.FillColor = Color.FromName(shapeColorOFF);
            ovalShape21.FillColor = Color.FromName(shapeColorOFF);
            ovalShape22.FillColor = Color.FromName(shapeColorON);
            ovalShape23.FillColor = Color.FromName(shapeColorON);
            ovalShape24.FillColor = Color.FromName(shapeColorOFF);
            ovalShape25.FillColor = Color.FromName(shapeColorOFF);
    }
        else if (counter == 4)
        {

            ovalShape1.FillColor = Color.FromName(shapeColorOFF);
            ovalShape2.FillColor = Color.FromName(shapeColorOFF);
            ovalShape3.FillColor = Color.FromName(shapeColorON);
            ovalShape4.FillColor = Color.FromName(shapeColorON);
            ovalShape5.FillColor = Color.FromName(shapeColorOFF);
            ovalShape6.FillColor = Color.FromName(shapeColorOFF);
            ovalShape7.FillColor = Color.FromName(shapeColorOFF);
            ovalShape8.FillColor = Color.FromName(shapeColorOFF);
            ovalShape9.FillColor = Color.FromName(shapeColorOFF);
            ovalShape10.FillColor = Color.FromName(shapeColorON);
            ovalShape11.FillColor = Color.FromName(shapeColorON);
            ovalShape12.FillColor = Color.FromName(shapeColorOFF);
            ovalShape13.FillColor = Color.FromName(shapeColorOFF);
            ovalShape14.FillColor = Color.FromName(shapeColorOFF);
            ovalShape15.FillColor = Color.FromName(shapeColorOFF);
            ovalShape16.FillColor = Color.FromName(shapeColorOFF);
            ovalShape17.FillColor = Color.FromName(shapeColorON);
            ovalShape18.FillColor = Color.FromName(shapeColorON);
            ovalShape19.FillColor = Color.FromName(shapeColorOFF);
            ovalShape20.FillColor = Color.FromName(shapeColorOFF);
            ovalShape21.FillColor = Color.FromName(shapeColorOFF);
            ovalShape22.FillColor = Color.FromName(shapeColorOFF);
            ovalShape23.FillColor = Color.FromName(shapeColorON);
            ovalShape24.FillColor = Color.FromName(shapeColorON);
            ovalShape25.FillColor = Color.FromName(shapeColorOFF);
    }
        else if (counter == 5)
        {

            ovalShape1.FillColor = Color.FromName(shapeColorOFF);
            ovalShape2.FillColor = Color.FromName(shapeColorOFF);
            ovalShape3.FillColor = Color.FromName(shapeColorOFF);
            ovalShape4.FillColor = Color.FromName(shapeColorON);
            ovalShape5.FillColor = Color.FromName(shapeColorON);
            ovalShape6.FillColor = Color.FromName(shapeColorOFF);
            ovalShape7.FillColor = Color.FromName(shapeColorOFF);
            ovalShape8.FillColor = Color.FromName(shapeColorOFF);
            ovalShape9.FillColor = Color.FromName(shapeColorON);
            ovalShape10.FillColor = Color.FromName(shapeColorON);
            ovalShape11.FillColor = Color.FromName(shapeColorOFF);
            ovalShape12.FillColor = Color.FromName(shapeColorOFF);
            ovalShape13.FillColor = Color.FromName(shapeColorOFF);
            ovalShape14.FillColor = Color.FromName(shapeColorON);
            ovalShape15.FillColor = Color.FromName(shapeColorON);
            ovalShape16.FillColor = Color.FromName(shapeColorOFF);
            ovalShape17.FillColor = Color.FromName(shapeColorOFF);
            ovalShape18.FillColor = Color.FromName(shapeColorOFF);
            ovalShape19.FillColor = Color.FromName(shapeColorON);
            ovalShape20.FillColor = Color.FromName(shapeColorON);
            ovalShape21.FillColor = Color.FromName(shapeColorOFF);
            ovalShape22.FillColor = Color.FromName(shapeColorOFF);
            ovalShape23.FillColor = Color.FromName(shapeColorOFF);
            ovalShape24.FillColor = Color.FromName(shapeColorON);
            ovalShape25.FillColor = Color.FromName(shapeColorON);
    }
        else if (counter == 6)
        {

            ovalShape1.FillColor = Color.FromName(shapeColorOFF);
            ovalShape2.FillColor = Color.FromName(shapeColorOFF);
            ovalShape3.FillColor = Color.FromName(shapeColorOFF);
            ovalShape4.FillColor = Color.FromName(shapeColorOFF);
            ovalShape5.FillColor = Color.FromName(shapeColorON);
            ovalShape6.FillColor = Color.FromName(shapeColorOFF);
            ovalShape7.FillColor = Color.FromName(shapeColorOFF);
            ovalShape8.FillColor = Color.FromName(shapeColorOFF);
            ovalShape9.FillColor = Color.FromName(shapeColorOFF);
            ovalShape10.FillColor = Color.FromName(shapeColorON);
            ovalShape11.FillColor = Color.FromName(shapeColorOFF);
            ovalShape12.FillColor = Color.FromName(shapeColorOFF);
            ovalShape13.FillColor = Color.FromName(shapeColorOFF);
            ovalShape14.FillColor = Color.FromName(shapeColorOFF);
            ovalShape15.FillColor = Color.FromName(shapeColorON);
            ovalShape16.FillColor = Color.FromName(shapeColorOFF);
            ovalShape17.FillColor = Color.FromName(shapeColorOFF);
            ovalShape18.FillColor = Color.FromName(shapeColorOFF);
            ovalShape19.FillColor = Color.FromName(shapeColorOFF);
            ovalShape20.FillColor = Color.FromName(shapeColorON);
            ovalShape21.FillColor = Color.FromName(shapeColorOFF);
            ovalShape22.FillColor = Color.FromName(shapeColorOFF);
            ovalShape23.FillColor = Color.FromName(shapeColorOFF);
            ovalShape24.FillColor = Color.FromName(shapeColorOFF);
            ovalShape25.FillColor = Color.FromName(shapeColorON);
    }
        else if (counter == 7)
        {


            ovalShape1.FillColor = Color.FromName(shapeColorOFF);
            ovalShape2.FillColor = Color.FromName(shapeColorOFF);
            ovalShape3.FillColor = Color.FromName(shapeColorOFF);
            ovalShape4.FillColor = Color.FromName(shapeColorOFF);
            ovalShape5.FillColor = Color.FromName(shapeColorOFF);
            ovalShape6.FillColor = Color.FromName(shapeColorOFF);
            ovalShape7.FillColor = Color.FromName(shapeColorOFF);
            ovalShape8.FillColor = Color.FromName(shapeColorOFF);
            ovalShape9.FillColor = Color.FromName(shapeColorOFF);
            ovalShape10.FillColor = Color.FromName(shapeColorOFF);
            ovalShape11.FillColor = Color.FromName(shapeColorOFF);
            ovalShape12.FillColor = Color.FromName(shapeColorOFF);
            ovalShape13.FillColor = Color.FromName(shapeColorOFF);
            ovalShape14.FillColor = Color.FromName(shapeColorOFF);
            ovalShape15.FillColor = Color.FromName(shapeColorOFF);
            ovalShape16.FillColor = Color.FromName(shapeColorOFF);
            ovalShape17.FillColor = Color.FromName(shapeColorOFF);
            ovalShape18.FillColor = Color.FromName(shapeColorOFF);
            ovalShape19.FillColor = Color.FromName(shapeColorOFF);
            ovalShape20.FillColor = Color.FromName(shapeColorOFF);
            ovalShape21.FillColor = Color.FromName(shapeColorOFF);
            ovalShape22.FillColor = Color.FromName(shapeColorOFF);
            ovalShape23.FillColor = Color.FromName(shapeColorOFF);
            ovalShape24.FillColor = Color.FromName(shapeColorOFF);
            ovalShape25.FillColor = Color.FromName(shapeColorOFF);
    }

        if (counter == 7)
        {
            counter = 0;

However, I don't think that this approach will allow me to adjust the speed of each row of 5 lights individually... and going for 2x7 timers seems be a very poor idea too.

Thomas
  • 13
  • 1
  • 4
  • Since the code you are showing is working, can you show us what you have tried so far for the part which is not working now? – Olli Jan 30 '20 at 12:03
  • Do i understand this right: You would like to have a matrix of "lights" and it should look like the lights get turned on from the top left to the bottom right. And they should be turned on one at a time and also turn off one at a time (with a slight delay), so that it looks like its traveling from the top left to the bottom right? – Olli Jan 30 '20 at 12:09
  • see answer in my post above – Thomas Jan 30 '20 at 19:08

1 Answers1

0

You need to create a model of your lights. Here 3 examples.

A model that accept next state based on an array

class ArrayModel : IEnumerable<bool>
{
    private readonly bool[] status;

    public ArrayModel(int lightCount)
    {
        status = new bool[lightCount];
    }

    public void Update(bool headLightStatus)
    {
        // update each cell of the array with the value of previous cell
        // we iterate in reverse order, otherwise it fills the buffer with the first value
        for (var i = status.Length - 1; i >= 1; i--)
            status[i] = status[i - 1];

        // set head light status
        status[0] = headLightStatus
    }

    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
    public IEnumerator<bool> GetEnumerator() => ((IEnumerable<bool>) status).GetEnumerator();
}

This create a lot of data copy. And can be improved with a Queue.

A model that accept next state based on a queue

class QueueModel : IEnumerable<bool>
{
    private readonly Queue<bool> status;

    public QueueModel(int lightCount)
    {
        // here queue is empty, the parameter is for the capacity
        status = new Queue<bool>(lightCount);

        // Set all light to off
        for (var i = 0; i < lightCount; i++)
            status.Enqueue(false);
    }

    public void Update(bool headLightStatus)
    {
        status.Dequeue(); // forget about the last status
        status.Enqueue(headLightStatus);
    }

    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
    public IEnumerator<bool> GetEnumerator() => status.GetEnumerator();
}

A static model base on an Array

This one is useful if the pattern is always the same.

class StaticArrayModel : IEnumerable<bool>
{
    private readonly bool[] _states;
    private int _startIndex;

    /// <summary>
    /// Constructor
    /// </summary>
    /// <param name="states">Initial states</param>
    public StaticArrayModel(IEnumerable<bool> states)
    {
        _states = states.ToArray();
    }

    /// <summary>
    /// Made light move forward 
    /// </summary>
    public void Increment()
    {
        _startIndex++;
        if (_startIndex == _states.Length)
            _startIndex = 0;
    }

    /// <summary>
    /// Made light move backward 
    /// </summary>
    public void Decrement()
    {
        _startIndex--;
        if (_startIndex < 0)
            _startIndex = _states.Length - 1;
    }

    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
    public IEnumerator<bool> GetEnumerator()
    {
        for (var i = 0; i < _states.Length; i++)
        {
            var j = i + _startIndex;
            j %= _states.Length;
            yield return _states[j];
        }
    }
}

Two last are known as Circular/Sliding buffers.

Update the view

I will not build a full MVC here, just show how the view can be updated:

private readonly QueueModel model = new QueueModel(2);
private readonly Control[] ovalShapes = new [] {ovalshape1, ovalshape1};

private void timer1_Tick(object sender, EventArgs e)
{
    model.Update(GetHeadLightStatus()); // true, false, random, you choose
    var i = 0;
    foreach (var status in model)
    {
      ovalShapes[i].IsVisible = status;
      i++;
    }
}
Orace
  • 7,822
  • 30
  • 45
  • I will attempt to implement your array code. however, it may take a while as I'm very new to C#. It would be very helpful if you could detail how you would create a matrix w 5 slots and cycle them through e.g. TRUE.FALSE.FALSE.FALSE.FALSE --> TRUE.TRUE.FALSE.FALSE.FALSE--> FALSE.TRUE.TRUE.FALSE.FALSE-->FALSE.FALSE.TRUE.TRUE.FALSE-->FALSE.FALSE.FALSE.TRUE.TRUE-->FALSE.FALSE.FALSE.FALSE.TRUE-->FALSE.FALSE.FALSE.FALSE.FALSE. Also, would you place this array in a timer to maintain the animation or is there another way of regulating speed? Thanks a lot! – Thomas Jan 30 '20 at 20:24
  • @Thomas, I added the `StaticArrayModel` that keep the same pattern running. About animation and timing, please ask a new question if needed. Timer are great for simple animation. Please read : https://stackoverflow.com/questions/12977111/why-use-windows-forms-timer-at-all – Orace Jan 31 '20 at 13:44