Random PShape without overlap

Hi there! I'm following a creative coding class and I'm stuck with an assignment. Luckily I've found a youtube video:

It has helped me a lot!

I've managed to create a star with a Pshape that has a random position. I've put it in draw so that I get multiple stars, only at the top of the screen. How can I make sure that the stars don't overlap? This is my code:

PShape ster, driehoek1, driehoek2;
float willekeurigx;
float willekeurigy;

void setup() {
  background(255);
  size(700, 500, P2D);
  frameRate(8);
}

void draw() {
  fill(255,255,0);
  noStroke();

  willekeurigx = random(width);
  willekeurigy = random(height/2);

  // ster
  driehoek1= createShape(TRIANGLE,0,0,25,-50,50,0);
  driehoek2= createShape(TRIANGLE,0, -35, 25, 15, 50, -35);

  //objecten aanmaken
  ster =createShape(GROUP);
  ster.addChild(driehoek1);
  ster.addChild(driehoek2);

  shape (ster, willekeurigx, willekeurigy);
}

And is there also a code that manages the space between the stars?

Thank you very much!

Izabella

Tagged:

Answers

  • Please format your code.
    Select your code and press ctrl + o to indent. Leave a line above and below.

  • I'm sorry I don't understand! When I press crtl + o I get a window to attach a file?

  • You can press that "C" button then, that should work.

  • @izabella1992

    Here is an example of how to do it. You will see that you will run into an infinite loop and your program will start misbehaving approximately after you run out of space to put any new stars. You need to implement a checking step so for your program to stop drawing stars at that point.

    Notice I move some functions calls to setup as they do not need to be called in draw which is running 60fps.

    Kf

    PShape ster, driehoek1, driehoek2; 
    float willekeurigx; 
    float willekeurigy;
    
    FloatList allXs;
    FloatList allYs;
    int shapeRadius=50;  //Assuming your shape is enclosed by a circle of this diameter for overlapping checking
    
    void setup() { 
      background(255); 
      size(700, 500, P2D); 
      frameRate(8);
    
      allXs=new FloatList();
      allYs=new FloatList();
    
      fill(255, 255, 0); 
      noStroke();
    
      // ster
      driehoek1= createShape(TRIANGLE, 0, 0, 25, -50, 50, 0); 
      driehoek2= createShape(TRIANGLE, 0, -35, 25, 15, 50, -35);
    
      //objecten aanmaken 
      ster =createShape(GROUP); 
      ster.addChild(driehoek1); 
      ster.addChild(driehoek2);
    }  
    
    
    void draw() {   
    
      boolean found=true;
      while (found==true) {
        found=false;
        willekeurigx = random(width); 
        willekeurigy = random(height/2);
        for (int i=0;i<allXs.size();i++){
          float fnx=allXs.get(i);
          float fny=allYs.get(i);
    
          //  !!  Next line check if there is any overlap between current "about to be 
          //  !!  generated" shape and pre-existing shapes
          if (dist(fnx,fny,willekeurigx,willekeurigy)<shapeRadius){ found=true;}
        }    
      }
      allXs.append(willekeurigx);
      allYs.append(willekeurigy);
    
      shape (ster, willekeurigx, willekeurigy);
    }
    
  • You will see that you will run into an infinite loop

    gah! don't post code with infinite loops in it!

    the way around this is to have a count rather than a true/false flag. set it to 0 for false, 1000 for true. increment it on failure. exit loop when it reaches 1000.

  • don't post code with infinite loops in it

    But draw() is exactly that!

    @izabella1992 Or just draw a finite number of objects, say 10 for example.

    Kf

  • I'm really trying to understand what you did but I'm really new to this so I jus't cant figure it out! I will keep on trying to understand

  • I created two arrayList objects allXs and allYs and I use them to store the the placement of all the centers of the stars loaded so far in the sketch.

    now imagine what would you do if you want to add a new star in your sketch. What steps will you go through to accomplish your task? These is what I did.
    1. Generate a new random coordinate for the center of the new star that I am about to add, lines 36,37.
    2. Check if this coordinates for the center will overlap with current stars in my sketch. To do that, it is not enough to see i the new coordinates exist within my array objects (allXs,allYs) but I also need to check for overlap. Checking for overlap is based on a model. I assume you star could be contained on a circle of certain radius, based on the size of your star, line 44. What this line does is to calculate the distance between two points. If this distance is less than the sum of two radii (I am assuming two each star is a big circle) then the current generated coordinate is not good (I set found to be true). The while() loop in line 34 will exit only when there is not any overlapped detected with current shapes stored in the arrays (which happen to be the current shapes shown in the sketch).
    3. After exiting the while loop, then it is guaranteed that my recent random generated coordinates is a good center point for my next star that I am about to draw. Before I draw the start, I need to add this point to my array objects so any future overlap checking takes into account this new point that I am about to draw. lines 47 and 48.
    4. Now and finally, draw the star, line 50.

    Now, two points to consider.

    1. In my overlapping algorithm, I assume a star can be represented by a big fat circle. A better overlap checking is to actual check for the star "area" overlap. It is a bit more complicated and I will take more effort to implement that code, not impossible. However, did you see my solution for overlap checking ended up being one line of code? For other overlap code, check previous posts: https://forum.processing.org/two/search?Search=overlap

    2. You need to keep in mind @koogs suggestion which is very important. Point number three above will execute successfully only if there is any space left to draw a new star. In your case, and any case of the same nature when you are adding non-overlapping figures to a sketch, an area will contain a finite number of non-overlapping figures. After you fill the area, you won't be able to add any new stars. The while loop in line 34 will run forever and you will lose control of your draw function. So you need to figure a way to force exiting the while loop. @koogs suggested to count how many times a while loop has been running during every single overlap checking. f you have more questions regarding this, please ask below. I did not take into account this in my code because i didn't know what you wanted to do next... and it would be an excessive for you to figure out.

    Kf

  • This circle packing example might also be relevant!

  • You could use circle packing to get a nearly good enough result.

  • You could use "an invisible box" or circle around each star, and check if those overlap. But those would sometimes overlap even though the stars are not.

    A more exact solution "at least for stars" is cheeking every individual line of the star you're intending to draw towards every line that's been drawn so far.

    I'we used this function for that purpose...
    intersect

    Don't know why it works, or how to do the NAN thing in processing but anyways, it works.

    So.. you draw an invisible star, then start a loop and if you find an intersection you break the loop, randomize a new spot and start over until you find a spot where you go through the whole list of lines and don't find any intersections, and then you draw the actual star.

        boolean intersect(float x1,float y1,float x2,float y2,float x3,float y3,float x4,float y4) {
            float x,y;
            x = ((x1*y2-y1*x2)*(x3-x4)-(x1-x2)*(x3*y4-y3*x4))/((x1-x2)*(y3-y4)-(y1-y2)*(x3-x4));
            y = ((x1*y2-y1*x2)*(y3-y4)-(y1-y2)*(x3*y4-y3*x4))/((x1-x2)*(y3-y4)-(y1-y2)*(x3-x4));
            if (x==0||y==0) {
                return false;
            } else {
                if (x1>=x2) {
                    if (!(x2<=x&&x<=x1)) {return false;}
                } else {
                    if (!(x1<=x&&x<=x2)) {return false;}
                }
                if (y1>=y2) {
                    if (!(y2<=y&&y<=y1)) {return false;}
                } else {
                    if (!(y1<=y&&y<=y2)) {return false;}
                }
                if (x3>=x4) {
                    if (!(x4<=x&&x<=x3)) {return false;}
                } else {
                    if (!(x3<=x&&x<=x4)) {return false;}
                }
                if (y3>=y4) {
                    if (!(y4<=y&&y<=y3)) {return false;}
                } else {
                    if (!(y3<=y&&y<=y4)) {return false;}
                }
            }
            return true;
            }
    
Sign In or Register to comment.