Move multiple shapes individually

edited August 2016 in Questions about Code

Hi there, This is my first time posting so I hope everything is up to scratch with the guidelines. I am very new to programming also. What I am trying to achieve is basically import a txt file which contains dimensions for rectangles.

400 400
55 80 r1
40 90 r2

The first two dimensions are the size of a sheet. Everything after that are the rectangles to be imported. I want to display them initially on the right hand side and then be able to move them with the mouse anywhere. I'm struggling with various aspects of the problem: 1) Importing the dimensions and storing them so that they are accessible globally and not just within a function. 2) My use of draw() seems incorrect as it continuously draws the imported rectangles in the initial position.

Help with the overall problem and/or with the two mentioned aspects above would be greatly appreciated.


//float bx;
//float by;
//int boxSize = 20;
boolean overBox = false;
boolean locked = false;
float xOffset = 0.0; 
float yOffset = 0.0; 

void settings() {
  size( 1000, 500);
}

void setup() {
  String[] rects = loadStrings("rects.txt");
  String[] sheetDimensions = split(rects[0], " ");
  int sheetDimensionX = parseInt(sheetDimensions[0]);
  int sheetDimensionY = parseInt(sheetDimensions[1]);

  background(600);
  rectMode(RADIUS);
  drawTargetSheet(0, 0, sheetDimensionX, sheetDimensionY);
}

void draw() { 
  String[] rects = loadStrings("rects.txt");
  String[] sheetDimensions = split(rects[0], " ");
  int sheetDimensionX = parseInt(sheetDimensions[0]);
  int sheetDimensionY = parseInt(sheetDimensions[1]);

  for (int i = 1; i < rects.length; i++) {
    String[] list = split(rects[i], " ");
    int boxSizeX = parseInt(list[0]);
    int boxSizeY = parseInt(list[1]);
    println(boxSizeX);
    println(boxSizeY);
    drawTarget((width - boxSizeX), (height - boxSizeY), boxSizeX, boxSizeY);
  }
}

void drawTargetSheet(float xloc, float yloc, float xSize, float ySize) {
  fill(255, 255, 255);
  rect(xloc, yloc, xSize, ySize);
}

void drawTarget(float xloc, float yloc, int side1, int side2) {

  // Test if the cursor is over the box 
  if (mouseX > xloc-side1 && mouseX < xloc+side1 && 
    mouseY > yloc-side2 && mouseY < yloc+side2) {
    overBox = true;  
    if (!locked) { 
      stroke(255); 
      fill(150);
    }
  } else {
    fill(100);
    overBox = false;
  }

  rect(xloc, yloc, side1, side2);
}

void mousePressed() {
  if (overBox) { 
    locked = true;
  } else {
    locked = false;
  }
  //  xOffset = mouseX-xloc; 
  //  yOffset = mouseY-yloc;
}

void mouseDragged() {
  if (locked) {
    stroke(0);
    fill(500, 200, 0);
    //   bx = mouseX-xOffset; 
    //   by = mouseY-yOffset;
  }
}

void mouseReleased() {
  locked = false;
}

Tagged:

Answers

  • I've updated my code to use a class. Still doesn't have the functionality I want. It doesn't pick up that Im over the rectangle, that I've clicked or that I've dragged it. I feel I'm getting nowhere with it.

    float xloc;
    float yloc;
    int boxSizeX;
    int boxSizeY;
    boolean overBox = false;
    boolean locked = false;
    float xOffset = 0.0; 
    float yOffset = 0.0; 
    String rects[] = new String[99999];
    String sheetDimensions[] = new String[99999];
    
    Rec myRec;
    
    void settings() {
      size( 1000, 500);
    }
    
    void setup() {
      rects = loadStrings("rects.txt");
      sheetDimensions = split(rects[0], " ");
      int sheetDimensionX = parseInt(sheetDimensions[0]);
      int sheetDimensionY = parseInt(sheetDimensions[1]);
    
      drawTargetSheet(0, 0, sheetDimensionX, sheetDimensionY);
      for (int i = 1; i < rects.length; i++) {
        String[] list = split(rects[i], " ");
        boxSizeX = parseInt(list[0]);
        boxSizeY = parseInt(list[1]);
        xloc = width - boxSizeX;
        yloc = boxSizeY* i *2;
      }
      
      myRec = new Rec(color(550), xloc, yloc, boxSizeX, boxSizeY);
      
    }
    
    void draw() { 
      
        if (mouseX > xloc-boxSizeX && mouseX < xloc+boxSizeX && 
          mouseY > yloc-boxSizeY && mouseY < yloc+boxSizeY) {
          overBox = true;  
        } 
        myRec.display();
        myRec.mousePressed();
        myRec.mouseDragged();
        myRec.mouseReleased();
         // drawRect(xloc, yloc, boxSizeX, boxSizeY);
    }
    
    class Rec {
     color c;
     float xPos;
     float yPos;
     int xSide;
     int ySide;
     
       Rec(color tempC, float tempXPos, float tempYPos, int tempXSide, int tempYSide) {
         xPos = tempXPos;
         yPos = tempYPos;
         xSide = tempXSide;
         ySide = tempYSide;
       }
       
       void display() {
         fill(c);
         rect(xPos, yPos, xSide, ySide);
       }
       
       void mousePressed() {
         if (overBox) { 
           locked = true;
         } else {
           locked = false;
         }
         xOffset = mouseX-xloc; 
         yOffset = mouseY-yloc;
         println(xOffset);
         println(yOffset);
       }
    
       void mouseDragged() {
         if (locked) {
           stroke(0);
           fill(500, 200, 0);
           xloc = mouseX-xOffset; 
           yloc = mouseY-yOffset;
          }
        }
    
        void mouseReleased() {
          locked = false;
        }
      
    }
    
    
    
    void drawTargetSheet(float xloc, float yloc, float xSize, float ySize) {
      fill(255, 255, 255);
      rect(xloc, yloc, xSize, ySize);
    }
    
    //void drawRect(float xloc, float yloc, int side1, int side2) {
    
      // Test if the cursor is over the box 
    //  if (mouseX > xloc-side1 && mouseX < xloc+side1 && 
    //    mouseY > yloc-side2 && mouseY < yloc+side2) {
     //   overBox = true;  
      //  if (!locked) { 
       //   stroke(255); 
       //   fill(150);
      //  }
     // } else {
      //  fill(100);
      //  overBox = false;
     // }
    
     // rect(xloc, yloc, side1, side2);
    //}
    
    
  • edited August 2016

    There is a example for drag, iirc menu File|Examples

    Remember that the mouse functions you have within a class are dead

    They only work outside the class (on the code level where draw is)

    So keep the functions inside the class as they are now and make functions with the same name on sketch level and here you for loop over your rectangles and call those in the class:

    pseudocode/////
    
    
    void mousePressed(){
    
        for loop with i.....
    
            loop over array of rects 
    
            myRec[i].mousePressed();
    
    
     pseudocode/////
    

    ===========================

    well, looking at your code there are some more flaws.

    Especially if you look at draw and setup: once you have multiple rects you want myRec to be an array of type Rec

    Rec[] myRec;

    in line 12.

    After line 19 say

    myRec= new Rec[rects.length];

    line33 must be inside the for loop and be:

    myRec[i]= ........
    
  • edited August 2016

    Hi Chrisir, Thanks very much for the reply. I've implemented the changes you suggested and also put a for loop in the draw() function but I'm not sure if I should have done that.

    Currently it loads in the rectangle BUT with a major problem:
    1) I'm not able to just move one rectangle individually. I'm able to move them but all of them move at once.

    Again, thanks for the help! :)

    float xloc;
    float yloc;
    int boxSizeX;
    int boxSizeY;
    boolean overBox = false;
    boolean locked = false;
    float xOffset = 0.0; 
    float yOffset = 0.0; 
    String rects[] = new String[99999];
    String sheetDimensions[] = new String[99999];
    
    Rec[] myRec;
    
    void settings() {
      size( 1000, 500);
    }
    
    void setup() {
      rects = loadStrings("rects.txt");
      myRec = new Rec[rects.length];
      sheetDimensions = split(rects[0], " ");
      int sheetDimensionX = parseInt(sheetDimensions[0]);
      int sheetDimensionY = parseInt(sheetDimensions[1]);
      drawTargetSheet(0, 0, sheetDimensionX, sheetDimensionY);
      
      for (int i = 1; i < rects.length; i++) {
        String[] list = split(rects[i], " ");
        boxSizeX = parseInt(list[0]);
        boxSizeY = parseInt(list[1]);
        xloc = width - boxSizeX;
        yloc = boxSizeY* i *2;
        
        myRec[i] = new Rec(color(150,150,150), xloc, yloc, boxSizeX, boxSizeY);
      }
    }
    
    void draw() {  
      background(0);
      drawTargetSheet(0, 0, 400, 700);
       for (int i = 1; i < rects.length; i++) {  
          myRec[i].display();
       }
    }
    
    void mousePressed() {
        for (int i = 1; i < rects.length; i++) {
            myRec[i].mousePressed();
        }
    }
    
    void mouseDragged() {
        for (int i = 1; i < rects.length; i++) {
            myRec[i].mouseDragged();
        }    
    }
    
    void mouseReleased() {
         for (int i = 1; i < rects.length; i++) {
            myRec[i].mouseReleased();
        } 
    }
    
    class Rec {
     color c;
     float xPos;
     float yPos;
     int xSide;
     int ySide;
     
       Rec(color tempC, float tempXPos, float tempYPos, int tempXSide, int tempYSide) {
         xPos = tempXPos;
         yPos = tempYPos;
         xSide = tempXSide;
         ySide = tempYSide;
       }
       
       void display() {
      
         fill(150,150,150);
         rect(xPos, yPos, xSide, ySide);
         
       }
       
       void mousePressed() {
         if (mouseEvent.getClickCount()==1){
         if (mouseX > xPos-xSide && mouseX < xPos+xSide && mouseY > yPos-ySide && mouseY < yPos+ySide) {
             overBox = true;
             if (overBox) { 
                 locked = true;
                 if (locked) {
                     xOffset = mouseX-xPos; 
                     yOffset = mouseY-yPos;
                 }
             } else {
             locked = false;
           }
         } 
         println(xOffset);
         println(yOffset);
         }
         //DOUBLE CLICK RETURNS TO ORIGINAL POSITION
         else if (mouseEvent.getClickCount()==2) {
            xPos = xloc;  
            yPos = yloc; 
         }
       }
    
       void mouseDragged() {
         if (locked) {
           xPos = mouseX-xOffset; 
           yPos = mouseY-yOffset;
          }
        }
    
        void mouseReleased() {
          locked = false;
        } 
    }
    
    void drawTargetSheet(float xloc, float yloc, float xSize, float ySize) {
      fill(255, 255, 255);
      rect(xloc, yloc, xSize, ySize);
    }
    
  • edited August 2016 Answer ✓

    you did extremely well, well done! Congrats!

    I changed a few minor things:

    • main point was your dragging issue. Here was the problem that stuff (variables) that belonged to ONE rect (inside the class) was before setup() and thus had global scope and was speaking for both rects. Bad. Hence both rects were moving.

    I am talking about these variables:

    boolean overBox = false;
    boolean locked = false;
    float xOffset = 0.0; 
    float yOffset = 0.0; 
    

    who belong inside the class, because they are properties of the rects which are different for each rect. So I changed that.

    Remark 1

    Speaking of scope: It is always nicer to give all variables as small a scope as possible. Hence I moved some variables from before setup inside setup.

    Especially:

    String rects[] = new String[99999];
    String sheetDimensions[] = new String[99999];
    

    They are only used in setup (in fact rects was used all over the place (in the form of rects.length) but I replaced this with myRec.length which is the same number).

    No need to init both with 99999 since loadStrings and split are taking care of the size of them automatically. In fact that would be enough:

      String rects[]; 
      String sheetDimensions[];
    

    Remark 2

    I also moved those

            float xloc;// moved into setup() 
            float yloc;
            int boxSizeX;
            int boxSizeY;
    

    into setup().

    Remark 3

    Not necessary to use drawTargetSheet in setup because background in draw is deleting it anyway and drawTargetSheet is used in draw() already.

    Remark 4

    I also recommend to have all classes at the very end of the sketch (and no code coming after it), so I moved the function drawTargetSheet before the class. But this again is more a matter of the beauty and readability of the code. Which is very important in the long run.

    Sorry for answering so late.

    Best, Chrisir ;-)

    // the core data structure 
    Rec[] myRec;
    
    // ---------------------------------------------------
    
    void settings() {
      size( 1000, 500);
    }
    
    void setup() {
    
      String rects[] = new String[0]; // moved into setup() and changed 
      String sheetDimensions[] = new String[0]; // moved into setup() and changed 
    
      rects = loadStrings("rects.txt");
      myRec = new Rec[rects.length];
      sheetDimensions = split(rects[0], " ");
    
      int sheetDimensionX = parseInt(sheetDimensions[0]);
      int sheetDimensionY = parseInt(sheetDimensions[1]);
    
      // drawTargetSheet(0, 0, sheetDimensionX, sheetDimensionY); // !!!!!
    
      for (int i = 1; i < rects.length; i++) {
        String[] list = split(rects[i], " ");
    
        // ALL moved into setup() 
        float xloc;// moved into setup() 
        float yloc;
        int boxSizeX;
        int boxSizeY;
    
        boxSizeX = parseInt(list[0]);
        boxSizeY = parseInt(list[1]);
        xloc = width - boxSizeX;
        yloc = boxSizeY* i *2;
    
        myRec[i] = new Rec(color(150, 150, 150), 
          xloc, yloc, 
          boxSizeX, boxSizeY);
      }
    }
    
    void draw() {  
      background(0);
      drawTargetSheet(0, 0, 400, 700);
      for (int i = 1; i < myRec.length; i++) {  
        myRec[i].display();
      }
    }
    
    // ------------------------------------------------------
    // other functions 
    
    void mousePressed() {
      for (int i = 1; i < myRec.length; i++) {
        myRec[i].mousePressed();
      }
    }
    
    void mouseDragged() {
      for (int i = 1; i < myRec.length; i++) {
        myRec[i].mouseDragged();
      }
    }
    
    void mouseReleased() {
      for (int i = 1; i < myRec.length; i++) {
        myRec[i].mouseReleased();
      }
    }
    
    void drawTargetSheet(float xloc, float yloc, float xSize, float ySize) {
      fill(255, 255, 255);
      rect(xloc, yloc, xSize, ySize);
    }
    
    // ==============================================================
    
    class Rec {
    
      color c;
    
      float xPos;
      float yPos;
      int xSide;
      int ySide;
    
      // moved these 6 !!! lines  here !!!!!!!!!!!!!!!!!!!!!!!!!!! 
      boolean overBox = false;
      boolean locked = false;
      float xOffset = 0.0; 
      float yOffset = 0.0; 
    
      float xloc;// moved into setup() 
      float yloc;
    
      Rec(color tempC, 
        float tempXPos, float tempYPos, 
        int tempXSide, int tempYSide) {
    
        c = tempC; 
    
        xPos = tempXPos;
        yPos = tempYPos;
        xSide = tempXSide;
        ySide = tempYSide;
    
        xloc=xPos; 
        yloc=yPos;
      }//constr
    
      void display() {
        // fill(150, 150, 150);
        fill(c);
        rect(xPos, yPos, 
          xSide, ySide);
      }
    
      void mousePressed() {
    
        if (mouseEvent.getClickCount()==1) {
    
          if (mouseX > xPos-xSide && mouseX < xPos+xSide &&
            mouseY > yPos-ySide && mouseY < yPos+ySide) {
    
            overBox = true;
            if (overBox) { 
              locked = true;
              if (locked) {
                xOffset = mouseX-xPos; 
                yOffset = mouseY-yPos;
              }
            } else {
              locked = false;
            }
          } 
          println(xOffset);
          println(yOffset);
        }
        //DOUBLE CLICK RETURNS TO ORIGINAL POSITION
        else if (mouseEvent.getClickCount()==2) {
          xPos = xloc;  
          yPos = yloc;
        }
      }
    
      void mouseDragged() {
        if (locked) {
          xPos = mouseX-xOffset; 
          yPos = mouseY-yOffset;
        }
      }
    
      void mouseReleased() {
        locked = false;
      }
    } // class 
    //
    
  • You sir are a hero! Can't thank you enough! Have a nice day :)

  • And you!

    ;-)

  • the double click resets both rects (since we don't check where the mouse is, over a rect or not)

    use a random color in line 38

    and a nice color for the target sheet

    ;-)

  • Answer ✓

    also xloc, yloc is not only used in setup but totally separately in the class too (just the same names, but different thing) to store the initial position for the double click

Sign In or Register to comment.