Delete leftmost circle on the canvas

Viewed 38

I was able to write a code that draws different circles on a canvas and i need to find a way i could delete the leftmost circle when any key is pressed. i've been at this for hours and i feel like i am close to the answer. i am most klikely going to look for the array whenever a key is pressed and delete the array position.

float colour = random(256);
final int DIAM = 20;
final int MAX_NUM = 1000;
int numPointsX = 0;
int numPointsY = 0;
int [] xPos = new int[MAX_NUM];
int [] yPos = new int [MAX_NUM];
boolean start = false;


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

void draw() {
  background(150);
  fill(random(256), random(256), random(256));
  for (int i=0; i<numPointsX; i++) {     
    circle(xPos[i], yPos[i], DIAM);
  }


  println(xPos[0]);
}

void mouseClicked() {
  insertXandY();
}

void insertXandY() {
  int x = mouseX;
  int y = mouseY;


  xPos[numPointsX] = x;
  yPos[numPointsY] = y;

  numPointsX += 1;
  numPointsY += 1;
  start = true;
}









void printArrays() {
  println("X Positions");
  for (int i = 0; i < 20; i++) {
    println("\t" + xPos[i]);
  }
}

void keyPressed() {
  if (key == 'p') {
    printArrays();
  }
}
1 Answers

You are on the right track.

In broad terms you'd need two steps:

  1. find the smallest X
  2. delete the data associated with the smallest X

The 1st part is trivial:

  1. use a variable to keep track of the currently smallest value (initialised with a bigger than than your data has)
  2. iterate through each value
  3. compare each value with the current smallest:
  4. if it's bigger ignore
  5. if it's smallest: update the currently smallest value (and remember the index)
  6. at the end of the iteration the currently smallest value is the smallest possible value and index can be used to associate between x,y arrays (which are incremented in sync)

Here's a slightly modified version of your code to illustrate this:

float colour = random(256);
final int DIAM = 20;
final int MAX_NUM = 1000;
int numPoints = 0;
int [] xPos = new int[MAX_NUM];
int [] yPos = new int [MAX_NUM];


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

void draw() {
  background(150);
  fill(random(256), random(256), random(256));
  for (int i=0; i < numPoints; i++) {     
    circle(xPos[i], yPos[i], DIAM);
  }


}

void mouseClicked() {
  insertXandY();
}

void insertXandY() {
  int x = mouseX;
  int y = mouseY;


  xPos[numPoints] = x;
  yPos[numPoints] = y;

  numPoints++;
}

void deleteLeftMost(){
  // find leftmost index
  // start with a large X value
  int smallestX = width;
  int smallestXIndex = -1;
  // iterate through each X
  for(int i = 0 ; i < numPoints; i++){
    // if xPos[i] is smaller than the smallest value so far...
    if (xPos[i] < smallestX){
      // ...remember it's value and index
      smallestX = xPos[i];
      smallestXIndex = i;
    }
  }
  // delete the item at this index: fake it for now: move coordinates offscreen (to the right so left search still works)
  xPos[smallestXIndex] = width * 2;
}


void printArrays() {
  println("X Positions");
  for (int i = 0; i < 20; i++) {
    println("\t" + xPos[i]);
  }
}

void keyPressed() {
  if (key == 'p') {
    printArrays();
  }
  if (keyCode == DELETE || keyCode == BACKSPACE){
    deleteLeftMost();
  }
}

I've made a few of other minor adjustments:

  • deleted start since it was assigned but not used (when debugging delete anything that isn't necessary)
  • renamed numPointsX to numPoints and deleted numPointsY: you are using two arrays indeed, however there is only one index for each point that could be re-used to access each array
  • numPoints++ is shorthand for numPoints = numPoints + 1;

Also, I've used a hacky placeholder for the remove a point just visually. This means in terms of memory the xPos/yPos for deleted points will still be allocated.

To actually delete the array is a bit tricker since the array datatype does not change size, however you could manually put something together using subset() and concat(). You can achieve a similar effect to deleting an element by concatenating two subset array: from the start to the index to delete and from the index next to the one to delete to the end of the array.

Something like this:

void setup(){
  println(deleteIndex(new int[]{1,2,3,4,5,6},-1));
  println(deleteIndex(new int[]{1,2,3,4,5,6},2));
  println(deleteIndex(new int[]{1,2,3,4,5,6},6));
}

int[] deleteIndex(int[] sourceArray, int indexToDelete){
  if(sourceArray == null){
    System.err.println("can't process null array");
    return null;
  }
  if(indexToDelete < 0){
    System.err.println("invalid index " + indexToDelete + "\nit's < 0");
    return null;
  }
  if(indexToDelete >= sourceArray.length){
    System.err.println("invalid index " + indexToDelete + "\nmax index = " + sourceArray.length);
    return null;
  }
  return concat(subset(sourceArray, 0, indexToDelete),
                subset(sourceArray, indexToDelete + 1, sourceArray.length - indexToDelete - 1));
}

It's a good idea to check arguments to a method to ensure they are valid and test with at least a few edge cases.

Here's a version of the above sketch using this delete method:

float colour = random(256);
final int DIAM = 20;
final int MAX_NUM = 1000;
int numPoints = 0;
int [] xPos = new int[MAX_NUM];
int [] yPos = new int [MAX_NUM];


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

void draw() {
  background(150);
  fill(random(256), random(256), random(256));
  for (int i=0; i < numPoints; i++) {     
    circle(xPos[i], yPos[i], DIAM);
  }


}

void mouseClicked() {
  insertXandY();
}

void insertXandY() {
  int x = mouseX;
  int y = mouseY;


  xPos[numPoints] = x;
  yPos[numPoints] = y;

  numPoints++;
}

void deleteLeftMost(){
  // find leftmost index
  // start with a large X value
  int smallestX = width;
  int smallestXIndex = -1;
  // iterate through each X
  for(int i = 0 ; i < numPoints; i++){
    // if xPos[i] is smaller than the smallest value so far...
    if (xPos[i] < smallestX){
      // ...remember it's value and index
      smallestX = xPos[i];
      smallestXIndex = i;
    }
  }
  // delete xPos item at this index
  xPos = deleteIndex(xPos, smallestXIndex);
  // delete yPos as well
  yPos = deleteIndex(yPos, smallestXIndex);
  // update size counter
  numPoints--;
}

int[] deleteIndex(int[] sourceArray, int indexToDelete){
  if(sourceArray == null){
    System.err.println("can't process null array");
    return null;
  }
  if(indexToDelete < 0){
    System.err.println("invalid index " + indexToDelete + "\nit's < 0");
    return null;
  }
  if(indexToDelete >= sourceArray.length){
    System.err.println("invalid index " + indexToDelete + "\nmax index = " + sourceArray.length);
    return null;
  }
  return concat(subset(sourceArray, 0, indexToDelete),
                subset(sourceArray, indexToDelete + 1, sourceArray.length - indexToDelete - 1));
}

void printArrays() {
  println("X Positions");
  for (int i = 0; i < xPos.length; i++) {
    println("\t" + xPos[i]);
  }
}

void keyPressed() {
  if (key == 'p') {
    printArrays();
  }
  if (keyCode == DELETE || keyCode == BACKSPACE){
    deleteLeftMost();
  }
}

If manually deleting an item from an array looks tedious it's because it is :) Array is meant to be fixed size: deleting an item actually allocates 3 arrays: two subset arrays and one for concatenation.

A better option is to use a dynamic sized array data structure like ArrayList. Speaking of data structures, to represent a point you can use the PVector class (which has x,y properties, but can also do much more).

You might have not encountered ArrayList and PVector yet, but there are plenty of resources out there (including CodingTrain/NatureOfCode videos). Here's an example using these:

final int DIAM = 20;
final int MAX_NUM = 1000;
ArrayList<PVector> points = new ArrayList<PVector>();

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

void draw() {
  background(150);
  fill(random(256), random(256), random(256));
  for (PVector point : points) {     
    circle(point.x, point.y, DIAM);
  }


}

void mouseClicked() {
  insertXandY();
}

void insertXandY() {
  if(points.size() < MAX_NUM){
    points.add(new PVector(mouseX, mouseY));
  }
}

void deleteLeftMost(){
  // find leftmost index
  // start with a large X value
  float smallestX = Float.MAX_VALUE;
  int smallestXIndex = -1;
  // iterate through each X
  for(int i = 0 ; i < points.size(); i++){
    PVector point = points.get(i);
    // if xPos[i] is smaller than the smallest value so far...
    if (point.x < smallestX){
      // ...remember it's value and index
      smallestX = point.x;
      smallestXIndex = i;
    }
  }
  // remove item from list
  points.remove(smallestXIndex);
}


void keyPressed() {
  if (key == 'p') {
    println(points);
  }
  if (keyCode == DELETE || keyCode == BACKSPACE){
    deleteLeftMost();
  }
}

Hopefully this step by step approach is easy to follow. Have fun learning !

Related