For loop doesn't load properly

Hello everyone!

I’m working on a sketch that looks for collision between a grid of points and a random polygon. I’m trying to find a way to make sure the colliding points always match a chosen number.

because the polygon is always different, I didn’t know how to find a relationship between the polygon and the grid, so my attempt is a For Loop that keeps drawing a new polygon until the colliding points match my number.

The sketch itself works fine and loads immediately, when I use this condition:

for (; count < 220;) { }

With the following condition, it works sometimes (sometimes the browser will load forever):

for (; count < 170 || count > 220;) { }

And with the following condition, the loading never finishes:

for (; 220 !== count;) { }

I was wondering if there is a way to make sure the loading does finish? I don’t mind waiting for a while, but as of now it seems my browser doesn’t intent to. I’m also open to other suggestions or approaches that have the same outcome. See full code below. I have used the p5.collide2d.js library.

Also, this is my first post :tada:.

function setup() {

  const sides = 8;
  const radius = 400;
  var step = (PI * 2) / sides;

  var hit = true;
  var count = 0;
  var polyA = [];

  createCanvas(1600, 1120);
  translate(560, 560);

  for (; 220 !== count;) {

    background('blue'); // clear last polygon
    polyA.splice(0, sides); // clears the array

    beginShape();

    for (var i = 0; i < sides; i++) { // this loop draws the polygon
      var x = Math.cos(i * step) * (radius - random(0, radius));
      var y = Math.sin(i * step) * (radius - random(0, radius));

      polyA.push(createVector(x, y)); // add vectors to array

      noFill();
      stroke('white');
      strokeWeight(1);
      vertex(x, y);
      ellipse(x, y, 10, 10);

    }

    endShape(CLOSE);

    for (var px = 0; px <= width; px += 20) { // this loop checks for collision
      for (var py = 0; py <= height; py += 20) {

        hit = (collidePointPoly(px - 560, py - 560, polyA));

        if (hit) {
          stroke('aqua'); strokeWeight(10);
          count++; // counts collision

        }

        else {
          stroke('aqua'); strokeWeight(2);

        }

        point(px - 560, py - 560);

      }
    }
  }

  // TEXT

  noStroke();
  fill('white');
  textSize(30);

  text('Sides Poly: ' + sides, 560, -350);
  text('Big Dots:  ' + count, 560, -300)

}

Welcome to the forums!

To clarify, you’re trying to to find a specific number of points inside the polygon?

Hi Gianni,
welcome to the p5 forum !

I don’t know if placing your shape on the top left corner is intentional, because you’re missing at least 3/4 of the sides of your poligon, because it is for now placed on the origin of the sketch (so 0,0).
So when the shape is extremely thin (ike in the pic below I took from your portion of code to generate a shape) or just create a shape such small that its colliding points don’t reach 220, explaining why you have troubles with your 2nd & 3rd attempt.

So actually I don’t really understand why you condition your for loop with the possibility of a hit, because if the shape doesn’t reach your limit, I suppose you do not care about it, so you can juste regenerate a new one if it’s not what you’re looking for

Okay, i get what you’re doing now. It gets the job done, but its definitely the brute-force method.

Interesting fact: It rerolls ~150 times on average.

The Bug: You never reset count, so, (probably within the first iteration), you overshoot 220 and the for loop misses the chance to ever be satisfied. (Fortunately openprocessing has infinite-loop protection or I never would have known).

Consider doing the check inside the if statement, breaking the loop once you’ve reached 220 hits:

        if (hit) {
          stroke('aqua'); strokeWeight(10);
          count++; // counts collision
          
          if(count > 220){
            break;
          }
        }
2 Likes

Hi,

Welcome to the community! :wink:

Few things before tackling the real problem :

  • Instead of saying translate(560, 560); if you want to translate to the middle of the screen, use translate(width / 2, height / 2); so your code more clear and adaptable

  • Then when you check the collision, also use collidePointPoly(px - width / 2, py - height / 2, polyA) and for the point(...) call

I think rather than using the p5.collide2d.js library, an alternative way to do this is to draw a random polygon on the screen with a distinct color (let’s say pure red).

Then you are going to loop for every points on the grid and check if the corresponding pixel is pure red. If yes, the point is in the polygon.

Repeat those steps until you find a polygon that matches the target number of points.

For example :

// Polygon settings
const sides = 10
const radius = 150

// The size of grid cells
const grid_spacing = 20;

// The target number of points to hit
const target_hit = 20;


function setup() {
  createCanvas(400, 400);
}

/*
Display a random polygon
*/
function randomPolygon() {
  // We choose red as the color
  fill(255, 0, 0);
  noStroke();
  
  push();
  translate(width / 2, height / 2);
  beginShape();
  for (let i = 0; i < sides; i++) {
    const angle = i * (TWO_PI / sides);
    const x = cos(angle) * random(radius);
    const y = sin(angle) * random(radius);

    vertex(x, y);
  }
  endShape();
  pop();
}

/*
Return the number of points inside the polygon
*/
function getPointsInsidePolygon() {
  let hit = 0;
  
  loadPixels();
  strokeWeight(5);
  for (let x = 0; x < width; x += grid_spacing) {
    for (let y = 0; y < height; y += grid_spacing) {
      let off = (y * width + x) * 4;

      // If the pixel is red
      if (pixels[off] == 255 && pixels[off + 1] == 0 && pixels[off + 2] == 0) {
        hit++;
      }
    }
  }
  
  return hit;
}


function draw() {
  background(255);
  
  randomPolygon();

  let hit_number = getPointsInsidePolygon();

  // Stop when found
  if (hit_number == target_hit) {
    noLoop();
  }
}

The downside of this is that you can’t really draw other things on the screen because it’s not going to be red anymore. It’s possible with the PGraphics equivalent in p5.js

2 Likes

Brilliant!! This works perfectly. Thank you so much. How did you measure the rerolls btw?

1 Like

Thank you for your reply! I have used the translate() function to reposition the polygon. Maybe you’ve missed that.

I had a “reroll” counter. Every time the main for-loop started again, I incremented. I tinkered with the sketch here if you want to take a look.

Good luck with your work! Can I ask what this things for?

Thank you so much for this approach and the tips you’ve shared! I will need a bit of time to study what you’ve done exactly but it seems like a good alternative. :slight_smile:

1 Like

Ahhh makes sense!

I’m working on a textile-print that will be made out of visual encryptions of text and a bit of data visualization. I’m using the dots inside the polygons as reference points for the visual encryption (yellow illustrations). Here’s a picture of one of the elements (I’ll remove the polygons):

Because the text that will go into this element is pre-defined I needed to make sure the reference points match. Thank you again :slight_smile:

2 Likes

Thats really cool! Whats the backstory? Why textiles?