Given the meaning of start, end and increment, I need an algorithm that counts up and down

Ok, I have a control that wants to fade in and out (continuously). To fade away, I adjust the transparency value of the control in the paint routine. So I set up a timer that starts and I set up the m_transparency member. The timer starts and it must move between the two given values ​​m_start, m_end. It can be 0-255.

eg. start 30, end 55, increment value = 5. It would look like this:

30, 35, 40, 45, 55, 50, 45, 40, 35, 30, 35, 40 .......

should also handle start 55, end 30.

Anyway, I wrote a terrible function that basically checks every condition (I move up or down and I got to the start, end, pivot point, etc.). It's ugly and I'm confused (triple nested ifs), but I can't figure out a cleaner way to do this and then check everything. Is there an easier way?

+2


source to share


8 answers


The next class makes it pretty easy. You will want to think about how you want it to behave around edge cases (for example this will lead to issue 55 for RangeScanner (30, 54, 5), but it is easy to change that to the behavior you want).



class RangeScanner
{
public:
    RangeScanner (int start, int end, unsigned int inc):
        value (start),
        lower (std :: min (start, end)),
        upper (std :: max (start, end)),
        increment (inc),
        incrementing (start <end)
    {
    }

    int nextValue ()
    {
        int ret = value;

        value + = incrementing? increment: -increment;

        if (value> = upper || value <= lower)
        {
            incrementing =! incrementing;
        }

        return ret;
    }

private:
    int value;
    const int lower;
    const int upper;
    const unsigned int increment;
    bool incrementing;
};
+5


source


This is how I approach it, a C based solution (which will of course work in C ++, but doesn't have any C ++ capabilities):

int nextVal (int curr, int min, int max, int *pStep) {
    // Handle situations where you want to turn around.

    if ((curr == min) || (curr == max)) {
        *pStep = -(*pStep);
        return curr + *pStep;
    }

    // Handle situation where you would exceed your bounds (just
    //   go to the bound).

    if (curr + *pStep < min) return min;
    if (curr + *pStep > max) return max;

    // Otherwise, just move within the bounds.

    return curr + *pStep;
}

      

 

int main(void) {
    int i;

    // Set up your variables here.

    int min = 30;
    int max = 55;
    int step = 5;

    // This is the running current value and we need to negate the step
    //   to force initial turn-around.

    int curr = min;
    step = -step;

    // Simple loop to demonstrate.

    printf ("%d\n", curr);
    for (i = 19; i > 0; i--) {
        curr = nextVal (curr, min,max,&step);
        printf ("%d\n", curr);
    }

    return 0;
}

      



Output:

30, 35, 40, 45, 50, 55, 50, 45, 40, 35, 30, 35, 40, 45, 50, 55, 50, 45, 40, 35

      

for your test case. It also intelligently handles sequences where the range is not an exact multiple of the increment (eg [7,40,10]):

7, 17, 27, 37, 40, 30, 20, 10, 7, 17, 27, 37, 40, 30, 20, 10, 7, 17, 27, 37

      

+4


source


Here the basic approach for ramping up is ramp-down as a function of time

.

int triangle(int time) {
    int d = m_end - m_start;
    return m_start + abs(((m_increment * time + d) % 2*d) - d);
}

      

+4


source


How about using a sine wave to get a more natural looking fade ...

#include <math.h>

class SineFader
{
public:
  SineFader(int min, int max)
    : base((double)min + ((double)(max - min) / 2))
    , range((double)(max - min) / 2)
    , theta(4.71)
    , speed(0.1)
  { }

  int getValue()
  {
    theta += speed;
    return (int)(base + (range * sin(theta)));
  }

private:
  double base, theta, range, speed;
};

      


Here's how you can use this in your code:

SineFader myfade(0, 55);

void onTimer()
{
   setTransparency(myfade.getValue());
}

      

+2


source


My version repeats the limit values: ... 50, 55, 55 , 50, ..., 35, 30, 30 , 35, ...

struct UpDown {
    int lo_val, hi_val, curr_val;
    int step;
};

void fade_in_out(struct UpDown *x) {
    x->curr_val += x->step;
    if ((x->curr_val > x->hi_val) || (x->curr_val < x->lo_val)) {
        x->step *= -1;
        x->curr_val += x->step;
    }
}

int main(void) {
    struct UpDown myControl = {30, 55, 30, 5};
    for (;;) {
        fade_in_out(&myControl);
    }
    return 0;
}

      

+1


source


This is a flexible solution, you can start anywhere in the range, and you can also indicate the direction you want to start in by making dir 1 or -1.

class Fader
{
public:
 Fader(int min, int max, int start, int dir = 1)
  : _min(min)
  , _max(max)
  , _val(start)
  , _dir(dir)
 { }

 int getValue()
 {
   if(_val <= min || _val >= _max)
     _dir = -_dir;

   _val += _dir;
   return _val;
  }

private:
  int _min, _max, _dir, _val;
};

      

0


source


This is how I did it. Seems pretty straightforward.

int computeTransparency(int start, int end, int& increment, int oldVal)
{
    if (start > end)
    {
        swap(start, end);
    }

    int newVal = oldVal + increment;
    bool goingUp = increment > 0;

    if (goingUp)
    {
        if (newVal >= end)
        {
            newVal = end;
            increment = -increment;
        }
    }
    else
    {
        if (newVal <= start)
        {
            newVal = start;
            increment = -increment;
        }
    }

    return newVal;
}

      

0


source


Here's another approach, bouncing between start and start + span in increments, with a helper function:

// Goes from start to start + span, and repeats.
int ramp(start, increment, span) {
  static int lastval = start;
  lastval += increment;
  lastval = lastval % (span + 1);
  return lastval;
}

// Goes from start up to start+span and back down, and repeats.
int bounce(start, increment, span) {
  val = ramp(0, increment, 2*span - 1);
  if (val > span) val = span - val;
  return val + start;
}

      

Basically, this is creating an ever-increasing line and then using the MOD function to slice it into a sawtooth and then reflecting the top half of the sawtooth indentation to make a zigzag.

Note that, unlike all other implemented implementations (unless I missed one), this one actually takes you the same distance along the zigzag, even if the increment is not split evenly - for example, for start 0, span 10, and step 3. it will go up 3 to 3, up 3-6, up 3 to 9, up 1 and down another 2 to 8, down 3 to 5, down 3 to 2, down 2 and up another 1 to 1 etc. - 3, 6, 9, 8, 5, 2, 1, 4, 7, 10, 7, 4, 1, .... And it also ensures that the numbers always fall into the right range and do the right thing, even if the increment is much larger than span or negative.

(You should probably rewrite this to put things like start, increment, and span somewhere in static storage, not in function arguments, because that would be pretty confusing if they change, but I'm lazy about that. And , indeed, it will still fall in the correct range and do a few reasonable things if they change - you can change the increment at any time and it will speed up or slow down without jumping.)

0


source







All Articles