# Scale up and down an ellipse doesn't work within a function

**URL:** <https://discourse.processing.org/t/scale-up-and-down-an-ellipse-doesnt-work-within-a-function/42564>\
**Category:** Electronics (Arduino, etc.)\
**Created:** [August 6, 2023, 6:36pm UTC](https://discourse.processing.org/t/scale-up-and-down-an-ellipse-doesnt-work-within-a-function/42564 "2023-08-06T18:36:55Z")\
**Posts on this page:** 1\
**Showing post:** 22

<div class="post-metadata">

**Author:** ![sterretje](https://avatars.discourse-cdn.com/v4/letter/s/cdc98d/32.png) [@sterretje](https://discourse.processing.org/u/sterretje)\
**Post date:** [August 17, 2023, 7:42am UTC](https://discourse.processing.org/t/scale-up-and-down-an-ellipse-doesnt-work-within-a-function/42564/22 "2023-08-17T07:42:07Z")

</div>

The whole script would be preferable in this case. I anyway went ahead because it is fun.

What I would implement is what is known as a finite state machine. Your program can be in one of a number of states. What I described in post #19 are the states. You can place those states in an _`enum`_ to give them sensible names.

```java
// states that our application can be in
enum FSM
{
  WAITTRIGGER,
    GROW,
    HOLD,
    SHRINK,
    COMPLETE
};

// variable to hold the current application state
FSM applicationState = FSM.WAITTRIGGER;

```

For the understanding of this post, an _`enum`_ is nothing more than a list of options. The variable _`applicationState`_ can only have those options.

In the _`draw()`_ method you can implement the state machine; the framework can look like below making use of a switch/case.

```java
void draw()
{
  background(0xFF404040);
  
  switch(applicationState)
  {
    case WAITTRIGGER:
    break;
    case GROW:
    break;
    case HOLD:
    break;
    case SHRINK:
    break;
    case COMPLETE:
    break;
  }
}

```

The intention is that once a step is complete, you go to another step. E.g. in _`WAITTRIGGER`_ you can go to _`GROW`_ when the mouse is pressed.

```java
  case WAITTRIGGER:
    if(mousePressed == true)
    {
      applicationState = FSM.GROW;
    }
    break;

```

For the implementation, I have written methods for each state; this keeps _`draw()`_ quite clean. Below the framework

```java
// states that our application can be in
enum FSM
{
  WAITTRIGGER,
    GROW,
    HOLD,
    SHRINK,
    COMPLETE
};

// variable to hold the current application state
FSM applicationState = FSM.WAITTRIGGER;

// diameter of circle to dislay
int diameter = 0;
// max diameter
int maxDiameter = 750;
// speed at which the circle must grow / shrink
int speed = 14;

// last time that ellipse was updated
int lastCycleTime;
// modify circle every 10 ms
int cycleInterval = 10;

// keep track when circle reached maximum size
int waitStartTime;
// keep circle at maximum size for 5 seconds
int waitDuration = 2000;
// flag
boolean isMax = false;

int clickTime = 0; // Variable to store the time of the click
boolean clicked = false; // Indicator variable to check if a click has occurred

// remember the last state of the mouse
boolean lastMouseState = false;

void setup()
{
  size(900, 900);
}

void draw()
{
  background(0xFF404040);

  switch(applicationState)
  {
  case WAITTRIGGER:
    waitTrigger();
    break;
  case GROW:
    grow();
    break;
  case HOLD:
    hold();
    break;
  case SHRINK:
    shrink();
    break;
  case COMPLETE:
    complete();
    break;
  }
}

void waitTrigger()
{
}

void grow()
{
}

void hold()
{
}

void shrink()
{
}

void complete()
{
}

```

And we can start implementing those methods. Below is the full code. See if you can follow the approach; if not, ask !

Notes:

1. When switching state, you set the variables that need changing for the next state. In above, in _`waitTrigger() `_ we set the _`clickTime`_ so we can display the lapsed time.
2. The above methods change the state when needed.
3. The above (main) methods handle (switching of) the state machine states; except for _`complete()`_. they call another method that does the actual work.
4. You can write a method called e.g. _`fsm()`_ that contains the below content of _`draw()`_ and call that method from draw to keep _`draw()`_ even cleaner. At this stage I don’t consider that necessary; it will become necessary when the size of _`draw()`_ grows out of hand and/or additional functionality is added to _`draw()`_.

```java

// states that our application can be in
enum FSM
{
  WAITTRIGGER,
    GROW,
    HOLD,
    SHRINK,
    COMPLETE
};

// variable to hold the current application state
FSM applicationState = FSM.WAITTRIGGER;

// diameter of circle to dislay
int diameter = 0;
// max diameter
int maxDiameter = 750;
// speed at which the circle must grow / shrink
int speed = 14;

// last time that ellipse was updated
int lastCycleTime;
// modify circle every 10 ms
int cycleInterval = 10;

// keep track when circle reached maximum size
int waitStartTime;
// keep circle at maximum size for 5 seconds
int waitDuration = 2000;
// flag
boolean isMax = false;

int clickTime = 0; // Variable to store the time of the click
boolean clicked = false; // Indicator variable to check if a click has occurred

// remember the last state of the mouse
boolean lastMouseState = false;

void setup()
{
  size(900, 900);
}

void draw()
{
  background(0xFF404040);

  switch(applicationState)
  {
  case WAITTRIGGER:
    waitTrigger();
    break;
  case GROW:
    grow();
    break;
  case HOLD:
    hold();
    break;
  case SHRINK:
    shrink();
    break;
  case COMPLETE:
    complete();
    break;
  }
}

//////////////////////////////////////////////////////////////
// Finite state machine main methods
//////////////////////////////////////////////////////////////

/*
Finite state machine: wait for trigger
 */
void waitTrigger()
{
  // wait for a change in state of the mouse
  if (mousePressed != lastMouseState)
  {
    // remember the last mouse state
    lastMouseState = mousePressed;

    // if the state went from not pressed to pressed
    if (mousePressed == true)
    {
      println("[WAITTRIGGER]Mouse pressed: Switching to GROW");
      applicationState = FSM.GROW;

      // setting the variables
      clickTime = millis();
    } //
    else
    {
      println("[WAITTRIGGER]Mouse released");
    }
  }
}

/*
Finite state machine: grow circle
 */
void grow()
{
  // display lapsed time
  zeitangabe();
  // grow the circle till it reached the maximum size
  if (growCircle() == true)
  {
    println("[GROW]Complete: Switching to HOLD");
    applicationState = FSM.HOLD;

    // setting the variables
    waitStartTime = millis();
    println("delay started @ " + str(waitStartTime));
  }
  // if the mouse was released
  if (mousePressed == false)
  {
    println("[GROW]Mouse released: Switching to COMPLETE");
    applicationState = FSM.COMPLETE;
  }
}

/*
Finite state machine: hold circle for a while
 */
void hold()
{
  // display lapsed time
  zeitangabe();
  // draw circle till hold time lapsed
  if (holdCircle() == true)
  {
    println("[HOLD]Complete: Switching to HOLD");
    applicationState = FSM.SHRINK;
  }
  // if the mouse was released
  if (mousePressed == false)
  {
    println("[HOLD]Mouse released: Switching to COMPLETE");
    applicationState = FSM.COMPLETE;
  }
}

/*
Finite state machine: shrink circle
 */
void shrink()
{
  // display lapsed time
  zeitangabe();
  // shrink the circle till it reached the minimum size
  if (shrinkCircle() == true)
  {
    println("[SHRINK]Complete: Switching to COMPLETE");
    applicationState = FSM.COMPLETE;
  }
  // if the mouse was released
  if (mousePressed == false)
  {
    println("[SHRINK]Mouse released: Switching to COMPLETE");
    applicationState = FSM.COMPLETE;
  }
}

/*
Finite state machine: process complete
 */
void complete()
{
  diameter = 0;
  println("[COMPLETE]Process complete: Switching to WAITTRIGGER");
  applicationState = FSM.WAITTRIGGER;
}

//////////////////////////////////////////////////////////////
// Finite state machine helpers
//////////////////////////////////////////////////////////////

/*
Grow circle
 Returns:
 true when circle has reached maximum size, else false
 */
boolean growCircle()
{
  // return value
  boolean rb = false;

  // draw ellipse
  drawCircle();

  // if it's time to update it
  if (millis() - lastCycleTime >= cycleInterval)
  {
    // remember the time that we did update
    lastCycleTime = millis();
    // grow ellipse for the next update
    diameter += speed;
  }

  if (diameter >= maxDiameter)
  {
    rb = true;
  }

  return rb;
}

/*
Shrink circle
 Returns:
 true when circle has reached minimum size, else false
 */
boolean shrinkCircle()
{
  // return value
  boolean rb = false;

  // draw ellipse
  drawCircle();

  // if it's time to update it
  if (millis() - lastCycleTime >= cycleInterval)
  {
    // remember the time that we did update
    lastCycleTime = millis();
    // shrink ellipse for the next update
    diameter -= speed;
  }

  if (diameter < 0)
  {
    rb = true;
  }

  return rb;
}

/*
Hold circle
 Returns:
 true when time to hold circle has lapsed, else false
 */
boolean holdCircle()
{
  boolean rb = false;
  // draw circle with the last diameter
  drawCircle();

  if (millis() - waitStartTime >= waitDuration)
  {
    rb = true;
    println("delay lapsed @ " + str(millis()));
  }

  return rb;
}

/*
Draw the circle
 */
void drawCircle()
{
  fill(0xFF000000);
  ellipse(width / 2, height / 2, diameter, diameter);
}

//////////////////////////////////////////////////////////////
// Other methods
//////////////////////////////////////////////////////////////

/*
Display lapsed time
 */
void zeitangabe()
{
  long elapsedTime = millis() - clickTime;
  fill(255);
  textAlign(CENTER);
  textSize(24);
  text("Time elapsed: " + elapsedTime + " ms", width / 2, 50);
}

```

---

_[View the full topic](https://discourse.processing.org/t/scale-up-and-down-an-ellipse-doesnt-work-within-a-function/42564)._
