Skip to content

Instantly share code, notes, and snippets.

@radiovisual
Last active January 2, 2023 18:14
Show Gist options
  • Save radiovisual/c8b2f33a660828dec6c94e2260ec70f6 to your computer and use it in GitHub Desktop.
Save radiovisual/c8b2f33a660828dec6c94e2260ec70f6 to your computer and use it in GitHub Desktop.

Revisions

  1. radiovisual revised this gist Jan 2, 2023. 1 changed file with 98 additions and 24 deletions.
    122 changes: 98 additions & 24 deletions processing.pde
    Original file line number Diff line number Diff line change
    @@ -23,7 +23,7 @@ void setup() {
    }

    // Smooth the polygon outlines
    smoothPolygons();
    smoothPolygons(polygons, 0);
    }

    void draw() {
    @@ -70,31 +70,105 @@ void tracePolygon(ArrayList<PVector> polygon, int x, int y, int recursionDepth)
    }
    }

    void smoothPolygons(ArrayList<PVector>[] polys, int depth) {
    if (depth > MAX_RECURSION_DEPTH) {
    return;
    }
    ArrayList<PVector>[] newPolys = new ArrayList[polys.length];
    for (int i = 0; i < polys.length; i++) {
    ArrayList<PVector> poly = polys[i];
    ArrayList<PVector> newPoly = new ArrayList<PVector>();
    PVector first = poly.get(0);
    PVector last = poly.get(poly.size()-1);
    PVector p = first;
    for (int j = 0; j < poly.size()-1; j++) {
    PVector q = poly.get(j+1);
    PVector mid = PVector.lerp(p, q, 0.5f);
    float d = getPerpendicularDistance(mid, poly);
    if (d > 5) {
    newPoly.add(p);
    newPoly.add(mid);
    }
    else {
    newPoly.add(p);
    }
    p = q;
    }
    if (!last.equals(first)) {
    newPoly.add(last);
    }
    newPolys[i] = newPoly;
    }
    smoothPolygons(newPolys, depth+1);
    }

    ArrayList<PVector> smoothPolygon(ArrayList<PVector> points, float epsilon) {
    // Check if the list of points is empty or has only one element
    if (points.size() < 2) return points;

    void smoothPolygons() {
    // Iterate through each polygon
    for (ArrayList<PVector> polygon : polygons) {
    // Create a new array to store the smoothed points
    ArrayList<PVector> smoothedPolygon = new ArrayList<PVector>();
    // Iterate through each point in the polygon
    for (int i = 0; i < polygon.size(); i++) {
    PVector p1 = polygon.get(i);
    PVector p2 = polygon.get((i + 1) % polygon.size());
    PVector p3 = polygon.get((i + 2) % polygon.size());
    // Compute the angle between the three points
    float angle = abs(PVector.angleBetween(p2.sub(p1), p3.sub(p2)));
    // If the angle is acute, add the middle point to the smoothed polygon
    if (angle < PI / 2) {
    smoothedPolygon.add(p2);
    } else {
    // If the angle is obtuse, add a new point halfway between the middle point and the point with the smallest distance
    PVector p4 = p2.lerp(dist(p1.x, p1.y, p2.x, p2.y) < dist(p2.x, p2.y, p3.x, p3.y) ? p1 : p3, 0.5);
    smoothedPolygon.add(p4);
    }
    // Create a new list to store the simplified version of the polygon
    ArrayList<PVector> simplifiedPolygon = new ArrayList<PVector>();

    // Find the point with the maximum distance from the line formed by the first and last points
    float dmax = 0;
    int index = 0;
    for (int i = 1; i < points.size() - 1; i++) {
    PVector point = points.get(i);
    float d = getPerpendicularDistance(point, points.get(0), points.get(points.size() - 1));
    if (d > dmax) {
    index = i;
    dmax = d;
    }
    // Replace the original polygon with the smoothed polygon
    polygon.clear();
    polygon.addAll(smoothedPolygon);
    }

    // If the maximum distance is greater than the specified epsilon, recursively simplify the line formed by the first and last points
    // and the point with the maximum distance
    if (dmax > epsilon) {
    // Recursively simplify the line formed by the first and last points
    ArrayList<PVector> line1 = smoothPolygon(new ArrayList<PVector>(points.subList(0, index + 1)), epsilon);
    ArrayList<PVector> line2 = smoothPolygon(new ArrayList<PVector>(points.subList(index, points.size())), epsilon);

    // Remove the last point from the first line and the first point from the second line
    line1.remove(line1.size() - 1);
    line2.remove(0);

    // Concatenate the two lines
    simplifiedPolygon.addAll(line1);
    simplifiedPolygon.addAll(line2);
    } else {
    // If the maximum distance is less than or equal to the specified epsilon, add the first and last points to the simplified polygon
    simplifiedPolygon.add(points.get(0));
    simplifiedPolygon.add(points.get(points.size() - 1));
    }

    return simplifiedPolygon;
    }

    float getPerpendicularDistance(int x, int y, int x1, int y1, int x2, int y2) {
    float A = x - x1;
    float B = y - y1;
    float C = x2 - x1;
    float D = y2 - y1;

    float dot = A * C + B * D;
    float len_sq = C * C + D * D;
    float param = dot / len_sq;

    float xx, yy;

    if (param < 0 || (x1 == x2 && y1 == y2)) {
    xx = x1;
    yy = y1;
    } else if (param > 1) {
    xx = x2;
    yy = y2;
    } else {
    xx = x1 + param * C;
    yy = y1 + param * D;
    }

    float dx = x - xx;
    float dy = y - yy;
    return sqrt(dx * dx + dy * dy);
    }

  2. radiovisual revised this gist Jan 2, 2023. 1 changed file with 2 additions and 16 deletions.
    18 changes: 2 additions & 16 deletions processing.pde
    Original file line number Diff line number Diff line change
    @@ -28,31 +28,17 @@ void setup() {

    void draw() {
    background(255);

    // Draw the polygons
    stroke(0);
    strokeWeight(1);
    noFill();
    for (ArrayList<PVector> polygon : polygons) {
    beginShape();
    for (PVector point : polygon) {
    vertex(point.x, point.y);
    }
    endShape(CLOSE);
    }

    // Fill the polygons with a random shade of red
    fill(random(255), 0, 0);
    noStroke();
    for (ArrayList<PVector> polygon : polygons) {
    beginShape();
    fill(random(255), 0, 0);
    for (PVector point : polygon) {
    vertex(point.x, point.y);
    }
    endShape(CLOSE);
    }
    }


    void tracePolygon(ArrayList<PVector> polygon, int x, int y, int recursionDepth) {
    // Add the current point to the polygon
    polygon.add(new PVector(x, y));
  3. radiovisual revised this gist Jan 2, 2023. 1 changed file with 37 additions and 12 deletions.
    49 changes: 37 additions & 12 deletions processing.pde
    Original file line number Diff line number Diff line change
    @@ -13,15 +13,17 @@ void setup() {
    // Iterate through each pixel in the image
    for (int y = 0; y < imageMask.height; y++) {
    for (int x = 0; x < imageMask.width; x++) {
    if (brightness(imageMask.get(x, y)) == 0 && brightness(imageMask.get(x, y)) == 255) {
    // If the pixel is black and hasn't been visited yet, start a new polygon and add it to the polygons array
    if (brightness(imageMask.get(x, y)) == 0 && brightness(imageMask.get(x, y)) != 255) {
    ArrayList<PVector> polygon = new ArrayList<PVector>();
    polygons.add(polygon);
    tracePolygon(polygon, x, y, 0);
    }
    // Smooth the polygon outlines
    smoothPolygons();
    }
    }

    // Smooth the polygon outlines
    smoothPolygons();
    }

    void draw() {
    @@ -30,8 +32,19 @@ void draw() {
    // Draw the polygons
    stroke(0);
    strokeWeight(1);
    noFill();
    for (ArrayList<PVector> polygon : polygons) {
    beginShape();
    for (PVector point : polygon) {
    vertex(point.x, point.y);
    }
    endShape(CLOSE);
    }

    // Fill the polygons with a random shade of red
    fill(random(255), 0, 0);
    noStroke();
    for (ArrayList<PVector> polygon : polygons) {
    fill(random(255), 0, 0);
    beginShape();
    for (PVector point : polygon) {
    vertex(point.x, point.y);
    @@ -40,28 +53,39 @@ void draw() {
    }
    }

    // Function to trace the outline of a polygon
    void tracePolygon(ArrayList<PVector> polygon, int x, int y, int recursionDepth) {
    // Add the current point to the polygon
    polygon.add(new PVector(x, y));
    // Set the current pixel to white to mark it as visited
    imageMask.set(x, y, color(255));

    // Check the pixels around the current point
    for (int dx = -1; dx <= 1; dx++) {
    for (int dy = -1; dy <= 1; dy++) {
    // Skip the current point and pixels outside the image
    if (x + dx < 0 || x + dx >= imageMask.width || y + dy < 0 || y + dy >= imageMask.height) {
    if (dx == 0 && dy == 0 || x + dx < 0 || x + dx >= imageMask.width || y + dy < 0 || y + dy >= imageMask.height) {
    continue;
    }
    // If the pixel is black and we haven't reached the maximum recursion depth, recursively trace the polygon from that point
    if (brightness(imageMask.get(x + dx, y + dy)) == 0 && recursionDepth < MAX_RECURSION_DEPTH) {
    tracePolygon(polygon, x + dx, y + dy, recursionDepth + 1);
    // If the pixel is black and hasn't been visited yet, recursively trace the polygon from that point
    if (brightness(imageMask.get(x + dx, y + dy)) == 0 && brightness(imageMask.get(x + dx, y + dy)) != 255) {
    // Check if the recursion depth is too large
    if (recursionDepth > MAX_RECURSION_DEPTH) {
    // If the recursion depth is too large, add a point halfway between the current point and the next point to the polygon
    PVector p1 = polygon.get(polygon.size() - 1);
    PVector p2 = new PVector(x + dx, y + dy);
    PVector p3 = p1.lerp(p2, 0.5);
    polygon.add(p3);
    } else {
    // If the recursion depth is not too large, recursively trace the polygon from the next point
    tracePolygon(polygon, x + dx, y + dy, recursionDepth + 1);
    }
    }
    }
    }
    }



    void smoothPolygons() {
    // Iterate through each polygon
    for (ArrayList<PVector> polygon : polygons) {
    @@ -75,8 +99,9 @@ void smoothPolygons() {
    // Compute the angle between the three points
    float angle = abs(PVector.angleBetween(p2.sub(p1), p3.sub(p2)));
    // If the angle is acute, add the middle point to the smoothed polygon
    smoothedPolygon.add(p2);
    if (!(angle < PI / 2)) {
    if (angle < PI / 2) {
    smoothedPolygon.add(p2);
    } else {
    // If the angle is obtuse, add a new point halfway between the middle point and the point with the smallest distance
    PVector p4 = p2.lerp(dist(p1.x, p1.y, p2.x, p2.y) < dist(p2.x, p2.y, p3.x, p3.y) ? p1 : p3, 0.5);
    smoothedPolygon.add(p4);
    @@ -86,4 +111,4 @@ void smoothPolygons() {
    polygon.clear();
    polygon.addAll(smoothedPolygon);
    }
    }
    }
  4. radiovisual revised this gist Jan 2, 2023. 1 changed file with 6 additions and 9 deletions.
    15 changes: 6 additions & 9 deletions processing.pde
    Original file line number Diff line number Diff line change
    @@ -13,16 +13,15 @@ void setup() {
    // Iterate through each pixel in the image
    for (int y = 0; y < imageMask.height; y++) {
    for (int x = 0; x < imageMask.width; x++) {
    if (brightness(imageMask.get(x, y)) == 0 && brightness(imageMask.get(x, y)) != 255) {
    if (brightness(imageMask.get(x, y)) == 0 && brightness(imageMask.get(x, y)) == 255) {
    ArrayList<PVector> polygon = new ArrayList<PVector>();
    polygons.add(polygon);
    tracePolygon(polygon, x, y, 0);
    }
    // Smooth the polygon outlines
    smoothPolygons();
    }
    }

    // Smooth the polygon outlines
    smoothPolygons();
    }

    void draw() {
    @@ -31,7 +30,6 @@ void draw() {
    // Draw the polygons
    stroke(0);
    strokeWeight(1);
    noFill();
    for (ArrayList<PVector> polygon : polygons) {
    fill(random(255), 0, 0);
    beginShape();
    @@ -52,7 +50,7 @@ void tracePolygon(ArrayList<PVector> polygon, int x, int y, int recursionDepth)
    for (int dx = -1; dx <= 1; dx++) {
    for (int dy = -1; dy <= 1; dy++) {
    // Skip the current point and pixels outside the image
    if (dx == 0 && dy == 0 || x + dx < 0 || x + dx >= imageMask.width || y + dy < 0 || y + dy >= imageMask.height) {
    if (x + dx < 0 || x + dx >= imageMask.width || y + dy < 0 || y + dy >= imageMask.height) {
    continue;
    }
    // If the pixel is black and we haven't reached the maximum recursion depth, recursively trace the polygon from that point
    @@ -77,9 +75,8 @@ void smoothPolygons() {
    // Compute the angle between the three points
    float angle = abs(PVector.angleBetween(p2.sub(p1), p3.sub(p2)));
    // If the angle is acute, add the middle point to the smoothed polygon
    if (angle < PI / 2) {
    smoothedPolygon.add(p2);
    } else {
    smoothedPolygon.add(p2);
    if (!(angle < PI / 2)) {
    // If the angle is obtuse, add a new point halfway between the middle point and the point with the smallest distance
    PVector p4 = p2.lerp(dist(p1.x, p1.y, p2.x, p2.y) < dist(p2.x, p2.y, p3.x, p3.y) ? p1 : p3, 0.5);
    smoothedPolygon.add(p4);
  5. radiovisual revised this gist Jan 2, 2023. 1 changed file with 4 additions and 4 deletions.
    8 changes: 4 additions & 4 deletions processing.pde
    Original file line number Diff line number Diff line change
    @@ -1,7 +1,7 @@
    PImage imageMask;
    ArrayList<ArrayList<PVector>> polygons;

    final int MAX_RECURSION_DEPTH = 10000;
    final int MAX_RECURSION_DEPTH = 1000;

    void setup() {
    size(512, 512);
    @@ -13,8 +13,7 @@ void setup() {
    // Iterate through each pixel in the image
    for (int y = 0; y < imageMask.height; y++) {
    for (int x = 0; x < imageMask.width; x++) {
    // If the pixel is black and hasn't been visited yet, start a new polygon and add it to the polygons array
    if (brightness(imageMask.get(x, y)) == 0 && brightness(imageMask.get(x, y)) != 255) {
    if (brightness(imageMask.get(x, y)) == 0 && brightness(imageMask.get(x, y)) != 255) {
    ArrayList<PVector> polygon = new ArrayList<PVector>();
    polygons.add(polygon);
    tracePolygon(polygon, x, y, 0);
    @@ -56,14 +55,15 @@ void tracePolygon(ArrayList<PVector> polygon, int x, int y, int recursionDepth)
    if (dx == 0 && dy == 0 || x + dx < 0 || x + dx >= imageMask.width || y + dy < 0 || y + dy >= imageMask.height) {
    continue;
    }
    // If the pixel is black and we haven't exceeded the maximum recursion depth, recursively trace the polygon from that point
    // If the pixel is black and we haven't reached the maximum recursion depth, recursively trace the polygon from that point
    if (brightness(imageMask.get(x + dx, y + dy)) == 0 && recursionDepth < MAX_RECURSION_DEPTH) {
    tracePolygon(polygon, x + dx, y + dy, recursionDepth + 1);
    }
    }
    }
    }


    void smoothPolygons() {
    // Iterate through each polygon
    for (ArrayList<PVector> polygon : polygons) {
  6. radiovisual revised this gist Jan 2, 2023. 1 changed file with 47 additions and 29 deletions.
    76 changes: 47 additions & 29 deletions processing.pde
    Original file line number Diff line number Diff line change
    @@ -1,10 +1,7 @@
    PImage imageMask;
    ArrayList<ArrayList<PVector>> polygons;

    // a higher value means that the function will be able to recurse more
    // times before it hits the maximum depth, which can use up more memory
    // and potentially slow down the program.
    final int MAX_RECURSION_DEPTH = 1000;
    final int MAX_RECURSION_DEPTH = 10000;

    void setup() {
    size(512, 512);
    @@ -24,10 +21,30 @@ void setup() {
    }
    }
    }

    // Smooth the polygon outlines
    smoothPolygons();
    }

    void draw() {
    background(255);

    // Draw the polygons
    stroke(0);
    strokeWeight(1);
    noFill();
    for (ArrayList<PVector> polygon : polygons) {
    fill(random(255), 0, 0);
    beginShape();
    for (PVector point : polygon) {
    vertex(point.x, point.y);
    }
    endShape(CLOSE);
    }
    }

    // Function to trace the outline of a polygon
    void tracePolygon(ArrayList<PVector> polygon, int x, int y, int depth) {
    void tracePolygon(ArrayList<PVector> polygon, int x, int y, int recursionDepth) {
    // Add the current point to the polygon
    polygon.add(new PVector(x, y));
    // Set the current pixel to white to mark it as visited
    @@ -39,36 +56,37 @@ void tracePolygon(ArrayList<PVector> polygon, int x, int y, int depth) {
    if (dx == 0 && dy == 0 || x + dx < 0 || x + dx >= imageMask.width || y + dy < 0 || y + dy >= imageMask.height) {
    continue;
    }
    // If the pixel is black and the recursion depth is less than the maximum allowed, recursively trace the polygon from that point
    if (brightness(imageMask.get(x + dx, y + dy)) == 0 && depth < MAX_RECURSION_DEPTH) {
    tracePolygon(polygon, x + dx, y + dy, depth + 1);
    // If the pixel is black and we haven't exceeded the maximum recursion depth, recursively trace the polygon from that point
    if (brightness(imageMask.get(x + dx, y + dy)) == 0 && recursionDepth < MAX_RECURSION_DEPTH) {
    tracePolygon(polygon, x + dx, y + dy, recursionDepth + 1);
    }
    }
    }
    }

    void draw() {
    background(255);

    // Draw the polygons
    stroke(0);
    strokeWeight(1);
    noFill();
    void smoothPolygons() {
    // Iterate through each polygon
    for (ArrayList<PVector> polygon : polygons) {
    beginShape();
    for (PVector point : polygon) {
    vertex(point.x, point.y);
    }
    endShape(CLOSE);
    }

    // Fill the polygons with a random shade of red
    for (ArrayList<PVector> polygon : polygons) {
    fill(random(255), 0, 0);
    beginShape();
    for (PVector point : polygon) {
    vertex(point.x, point.y);
    // Create a new array to store the smoothed points
    ArrayList<PVector> smoothedPolygon = new ArrayList<PVector>();
    // Iterate through each point in the polygon
    for (int i = 0; i < polygon.size(); i++) {
    PVector p1 = polygon.get(i);
    PVector p2 = polygon.get((i + 1) % polygon.size());
    PVector p3 = polygon.get((i + 2) % polygon.size());
    // Compute the angle between the three points
    float angle = abs(PVector.angleBetween(p2.sub(p1), p3.sub(p2)));
    // If the angle is acute, add the middle point to the smoothed polygon
    if (angle < PI / 2) {
    smoothedPolygon.add(p2);
    } else {
    // If the angle is obtuse, add a new point halfway between the middle point and the point with the smallest distance
    PVector p4 = p2.lerp(dist(p1.x, p1.y, p2.x, p2.y) < dist(p2.x, p2.y, p3.x, p3.y) ? p1 : p3, 0.5);
    smoothedPolygon.add(p4);
    }
    }
    endShape(CLOSE);
    // Replace the original polygon with the smoothed polygon
    polygon.clear();
    polygon.addAll(smoothedPolygon);
    }
    }
  7. radiovisual revised this gist Jan 2, 2023. 1 changed file with 33 additions and 87 deletions.
    120 changes: 33 additions & 87 deletions processing.pde
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,11 @@
    PImage imageMask;
    ArrayList<ArrayList<PVector>> polygons;

    // a higher value means that the function will be able to recurse more
    // times before it hits the maximum depth, which can use up more memory
    // and potentially slow down the program.
    final int MAX_RECURSION_DEPTH = 1000;

    void setup() {
    size(512, 512);
    imageMask = loadImage("imageMask.png");
    @@ -19,12 +24,27 @@ void setup() {
    }
    }
    }
    }

    // Smooth the polygon outlines
    smoothPolygons();

    // Fill the polygons with a random shade of red
    fill(random(255), 0, 0);
    // Function to trace the outline of a polygon
    void tracePolygon(ArrayList<PVector> polygon, int x, int y, int depth) {
    // Add the current point to the polygon
    polygon.add(new PVector(x, y));
    // Set the current pixel to white to mark it as visited
    imageMask.set(x, y, color(255));
    // Check the pixels around the current point
    for (int dx = -1; dx <= 1; dx++) {
    for (int dy = -1; dy <= 1; dy++) {
    // Skip the current point and pixels outside the image
    if (dx == 0 && dy == 0 || x + dx < 0 || x + dx >= imageMask.width || y + dy < 0 || y + dy >= imageMask.height) {
    continue;
    }
    // If the pixel is black and the recursion depth is less than the maximum allowed, recursively trace the polygon from that point
    if (brightness(imageMask.get(x + dx, y + dy)) == 0 && depth < MAX_RECURSION_DEPTH) {
    tracePolygon(polygon, x + dx, y + dy, depth + 1);
    }
    }
    }
    }

    void draw() {
    @@ -33,96 +53,22 @@ void draw() {
    // Draw the polygons
    stroke(0);
    strokeWeight(1);
    noFill();
    for (ArrayList<PVector> polygon : polygons) {
    beginShape();
    for (PVector point : polygon) {
    vertex(point.x, point.y);
    }
    endShape(CLOSE);
    }
    }



    // Function to smooth the polygon outlines
    void smoothPolygons() {
    // Iterate through each polygon
    // Fill the polygons with a random shade of red
    for (ArrayList<PVector> polygon : polygons) {
    // Create a new array to store the smoothed points
    ArrayList<PVector> smoothedPolygon = new ArrayList<PVector>();
    // Iterate through each point in the polygon
    for (int i = 0; i < polygon.size(); i++) {
    PVector p1 = polygon.get(i);
    PVector p2 = polygon.get((i + 1) % polygon.size());
    PVector p3 = polygon.get((i + 2) % polygon.size());
    // Compute the angle between the three points
    float angle = abs(PVector.angleBetween(p2.sub(p1), p3.sub(p2)));
    // If the angle is acute, add the middle point to the smoothed polygon
    if (angle < PI / 2) {
    smoothedPolygon.add(p2);
    } else {
    // If the angle is obtuse, add a new point halfway between the middle point and the point with the smallest distance
    PVector p4 = p2.lerp(dist(p1.x, p1.y, p2.x, p2.y) < dist(p2.x, p2.y, p3.x, p3.y) ? p1 : p3, 0.5);
    smoothedPolygon.add(p4);
    }
    }
    // Replace the original polygon with the smoothed polygon
    polygon.clear();
    polygon.addAll(smoothedPolygon);
    }
    }

    // Maximum recursion depth
    int maxRecursionDepth = 1000;

    // Function to trace the outline of a polygon
    void tracePolygon(ArrayList<PVector> polygon, int x, int y, int recursionDepth) {
    // Check the recursion depth
    if (recursionDepth > maxRecursionDepth) {
    return;
    }

    // Add the current point to the polygon if it hasn't already been visited
    if (brightness(imageMask.get(x, y)) == 0) {
    polygon.add(new PVector(x, y));
    // Set the current pixel to white to mark it as visited
    imageMask.set(x, y, color(255));
    }

    // Check the pixels around the current point
    for (int dx = -1; dx <= 1; dx++) {
    for (int dy = -1; dy <= 1; dy++) {
    // Skip the current point and pixels outside the image
    if (dx == 0 && dy == 0 || x + dx < 0 || x + dx >= imageMask.width || y + dy < 0 || y + dy >= imageMask.height) {
    continue;
    }
    // If the pixel is black and hasn't been visited yet, recursively trace the polygon from that point
    if (brightness(imageMask.get(x + dx, y + dy)) == 0) {
    tracePolygon(polygon, x + dx, y + dy, recursionDepth + 1);
    }
    }
    }
    }

    // Custom drawing function for the "cracks" effect
    void drawCracks(ArrayList<PVector> polygon) {
    noFill();
    strokeWeight(2);
    stroke(0);

    // Iterate through each point in the polygon
    for (int i = 0; i < polygon.size(); i++) {
    PVector p1 = polygon.get(i);
    PVector p2 = polygon.get((i + 1) % polygon.size());
    // Draw a line between the two points
    line(p1.x, p1.y, p2.x, p2.y);
    // Draw a series of smaller lines perpendicular to the main line
    for (int j = 1; j <= 4; j++) {
    float offset = j * 5;
    float angle = atan2(p2.y - p1.y, p2.x - p1.x);
    line(p1.x + offset * cos(angle + PI / 2), p1.y + offset * sin(angle + PI / 2), p2.x + offset * cos(angle + PI / 2), p2.y + offset * sin(angle + PI / 2));
    fill(random(255), 0, 0);
    beginShape();
    for (PVector point : polygon) {
    vertex(point.x, point.y);
    }
    endShape(CLOSE);
    }
    }


    }
  8. radiovisual revised this gist Jan 2, 2023. 1 changed file with 7 additions and 5 deletions.
    12 changes: 7 additions & 5 deletions processing.pde
    Original file line number Diff line number Diff line change
    @@ -22,22 +22,24 @@ void setup() {

    // Smooth the polygon outlines
    smoothPolygons();

    // Fill the polygons with a random shade of red
    fill(random(255), 0, 0);
    }

    void draw() {
    background(255);

    // Draw the polygons
    stroke(0);
    strokeWeight(1);
    for (ArrayList<PVector> polygon : polygons) {
    noStroke();
    beginShape();
    for (PVector point : polygon) {
    vertex(point.x, point.y);
    }
    fill(color(int(random(255)), 0, 0));
    endShape(CLOSE);
    }

    // Dont draw the mask image
    // image(imageMask, 0, 0);
    }


  9. radiovisual revised this gist Jan 2, 2023. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions processing.pde
    Original file line number Diff line number Diff line change
    @@ -32,12 +32,12 @@ void draw() {
    for (PVector point : polygon) {
    vertex(point.x, point.y);
    }
    fill(color(int(random(256)), 0, 0));
    fill(color(int(random(255)), 0, 0));
    endShape(CLOSE);
    }

    // Draw the image mask on top of the polygons
    image(imageMask, 0, 0);
    // Dont draw the mask image
    // image(imageMask, 0, 0);
    }


  10. radiovisual revised this gist Jan 2, 2023. 1 changed file with 2 additions and 1 deletion.
    3 changes: 2 additions & 1 deletion processing.pde
    Original file line number Diff line number Diff line change
    @@ -32,7 +32,7 @@ void draw() {
    for (PVector point : polygon) {
    vertex(point.x, point.y);
    }
    fill(color(random(256.0), 0.0, 0.0));
    fill(color(int(random(256)), 0, 0));
    endShape(CLOSE);
    }

    @@ -41,6 +41,7 @@ void draw() {
    }



    // Function to smooth the polygon outlines
    void smoothPolygons() {
    // Iterate through each polygon
  11. radiovisual revised this gist Jan 2, 2023. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion processing.pde
    Original file line number Diff line number Diff line change
    @@ -29,10 +29,10 @@ void draw() {
    for (ArrayList<PVector> polygon : polygons) {
    noStroke();
    beginShape();
    fill(color(random(256.0), 0.0, 0.0));
    for (PVector point : polygon) {
    vertex(point.x, point.y);
    }
    fill(color(random(256.0), 0.0, 0.0));
    endShape(CLOSE);
    }

  12. radiovisual revised this gist Jan 2, 2023. 1 changed file with 4 additions and 3 deletions.
    7 changes: 4 additions & 3 deletions processing.pde
    Original file line number Diff line number Diff line change
    @@ -22,8 +22,10 @@ void setup() {

    // Smooth the polygon outlines
    smoothPolygons();
    }

    // Iterate through each polygon and fill it with a random shade of red
    void draw() {
    // Draw the polygons
    for (ArrayList<PVector> polygon : polygons) {
    noStroke();
    beginShape();
    @@ -33,13 +35,12 @@ void setup() {
    }
    endShape(CLOSE);
    }
    }

    void draw() {
    // Draw the image mask on top of the polygons
    image(imageMask, 0, 0);
    }


    // Function to smooth the polygon outlines
    void smoothPolygons() {
    // Iterate through each polygon
  13. radiovisual revised this gist Jan 2, 2023. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion processing.pde
    Original file line number Diff line number Diff line change
    @@ -27,7 +27,7 @@ void setup() {
    for (ArrayList<PVector> polygon : polygons) {
    noStroke();
    beginShape();
    fill(color(random(256), 0, 0));
    fill(color(random(256.0), 0.0, 0.0));
    for (PVector point : polygon) {
    vertex(point.x, point.y);
    }
  14. radiovisual revised this gist Jan 2, 2023. 1 changed file with 5 additions and 17 deletions.
    22 changes: 5 additions & 17 deletions processing.pde
    Original file line number Diff line number Diff line change
    @@ -5,53 +5,41 @@ void setup() {
    size(512, 512);
    imageMask = loadImage("imageMask.png");



    // Create an empty array to store the polygons
    polygons = new ArrayList<ArrayList<PVector>>();

    // Iterate through each pixel in the image
    for (int y = 0; y < imageMask.height; y++) {
    for (int x = 0; x < imageMask.width; x++) {
    // If the pixel is black and hasn't been visited yet, start a new polygon and add it to the polygons array
    if (brightness(imageMask.get(x, y)) == 0) {
    if (brightness(imageMask.get(x, y)) == 0 && brightness(imageMask.get(x, y)) != 255) {
    ArrayList<PVector> polygon = new ArrayList<PVector>();
    polygons.add(polygon);
    tracePolygon(polygon, x * imageMask.width, y * imageMask.height, 0);
    tracePolygon(polygon, x, y, 0);
    }
    }
    }

    // Smooth the polygon outlines
    smoothPolygons();
    }

    void draw() {
    background(255);

    // Iterate through each polygon
    // Iterate through each polygon and fill it with a random shade of red
    for (ArrayList<PVector> polygon : polygons) {
    noStroke();

    // Draw the polygon
    beginShape();
    // Choose a random shade of red
    fill(color(random(256), 0, 0));
    for (PVector point : polygon) {
    vertex(point.x, point.y);
    }
    endShape(CLOSE);
    }
    }

    void draw() {
    // Draw the image mask on top of the polygons
    image(imageMask, 0, 0);
    }






    // Function to smooth the polygon outlines
    void smoothPolygons() {
    // Iterate through each polygon
  15. radiovisual revised this gist Jan 2, 2023. 1 changed file with 2 additions and 5 deletions.
    7 changes: 2 additions & 5 deletions processing.pde
    Original file line number Diff line number Diff line change
    @@ -31,22 +31,19 @@ void draw() {

    // Iterate through each polygon
    for (ArrayList<PVector> polygon : polygons) {
    // Choose a random shade of red
    fill(color(random(256), 0, 0));
    noStroke();

    // Draw the polygon
    beginShape();
    // Choose a random shade of red
    fill(color(random(256), 0, 0));
    for (PVector point : polygon) {
    vertex(point.x, point.y);
    }
    endShape(CLOSE);
    }

    // Draw the image mask on top of the polygons
    tint(255);
    blendMode(BLEND);

    image(imageMask, 0, 0);
    }

  16. radiovisual revised this gist Jan 2, 2023. 1 changed file with 5 additions and 0 deletions.
    5 changes: 5 additions & 0 deletions processing.pde
    Original file line number Diff line number Diff line change
    @@ -5,6 +5,8 @@ void setup() {
    size(512, 512);
    imageMask = loadImage("imageMask.png");



    // Create an empty array to store the polygons
    polygons = new ArrayList<ArrayList<PVector>>();

    @@ -42,6 +44,9 @@ void draw() {
    }

    // Draw the image mask on top of the polygons
    tint(255);
    blendMode(BLEND);

    image(imageMask, 0, 0);
    }

  17. radiovisual revised this gist Jan 2, 2023. 1 changed file with 14 additions and 5 deletions.
    19 changes: 14 additions & 5 deletions processing.pde
    Original file line number Diff line number Diff line change
    @@ -27,20 +27,29 @@ void setup() {
    void draw() {
    background(255);

    // Draw the image mask
    image(imageMask, 0, 0);

    // Iterate through each polygon
    for (ArrayList<PVector> polygon : polygons) {
    // Apply the "cracks" effect to the polygon
    drawCracks(polygon);
    // Choose a random shade of red
    fill(color(random(256), 0, 0));
    noStroke();

    // Draw the polygon
    beginShape();
    for (PVector point : polygon) {
    vertex(point.x, point.y);
    }
    endShape(CLOSE);
    }

    // Draw the image mask on top of the polygons
    image(imageMask, 0, 0);
    }






    // Function to smooth the polygon outlines
    void smoothPolygons() {
    // Iterate through each polygon
  18. radiovisual revised this gist Jan 2, 2023. 1 changed file with 25 additions and 9 deletions.
    34 changes: 25 additions & 9 deletions processing.pde
    Original file line number Diff line number Diff line change
    @@ -30,20 +30,17 @@ void draw() {
    // Draw the image mask
    image(imageMask, 0, 0);

    // Draw the polygons
    stroke(0);
    strokeWeight(1);
    noFill();
    // Iterate through each polygon
    for (ArrayList<PVector> polygon : polygons) {
    beginShape();
    for (PVector point : polygon) {
    vertex(point.x, point.y);
    }
    endShape(CLOSE);
    // Apply the "cracks" effect to the polygon
    drawCracks(polygon);
    }
    }





    // Function to smooth the polygon outlines
    void smoothPolygons() {
    // Iterate through each polygon
    @@ -104,6 +101,25 @@ void tracePolygon(ArrayList<PVector> polygon, int x, int y, int recursionDepth)
    }
    }

    // Custom drawing function for the "cracks" effect
    void drawCracks(ArrayList<PVector> polygon) {
    noFill();
    strokeWeight(2);
    stroke(0);

    // Iterate through each point in the polygon
    for (int i = 0; i < polygon.size(); i++) {
    PVector p1 = polygon.get(i);
    PVector p2 = polygon.get((i + 1) % polygon.size());
    // Draw a line between the two points
    line(p1.x, p1.y, p2.x, p2.y);
    // Draw a series of smaller lines perpendicular to the main line
    for (int j = 1; j <= 4; j++) {
    float offset = j * 5;
    float angle = atan2(p2.y - p1.y, p2.x - p1.x);
    line(p1.x + offset * cos(angle + PI / 2), p1.y + offset * sin(angle + PI / 2), p2.x + offset * cos(angle + PI / 2), p2.y + offset * sin(angle + PI / 2));
    }
    }
    }


  19. radiovisual revised this gist Jan 2, 2023. 1 changed file with 12 additions and 10 deletions.
    22 changes: 12 additions & 10 deletions processing.pde
    Original file line number Diff line number Diff line change
    @@ -24,24 +24,26 @@ void setup() {
    smoothPolygons();
    }



    void draw() {
    background(255);

    // Draw the image mask
    image(imageMask, 0, 0);

    // Draw the polygons
    stroke(0);
    strokeWeight(1);
    noFill();
    for (ArrayList<PVector> polygon : polygons) {
    beginShape();
    for (PVector point : polygon) {
    vertex(point.x, point.y);
    strokeWeight(1);
    noFill();
    for (ArrayList<PVector> polygon : polygons) {
    beginShape();
    for (PVector point : polygon) {
    vertex(point.x, point.y);
    }
    endShape(CLOSE);
    }
    endShape(CLOSE);
    }
    }


    // Function to smooth the polygon outlines
    void smoothPolygons() {
    // Iterate through each polygon
  20. radiovisual revised this gist Jan 2, 2023. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions processing.pde
    Original file line number Diff line number Diff line change
    @@ -15,7 +15,7 @@ void setup() {
    if (brightness(imageMask.get(x, y)) == 0) {
    ArrayList<PVector> polygon = new ArrayList<PVector>();
    polygons.add(polygon);
    tracePolygon(polygon, x, y, 0);
    tracePolygon(polygon, x * imageMask.width, y * imageMask.height, 0);
    }
    }
    }
    @@ -96,7 +96,7 @@ void tracePolygon(ArrayList<PVector> polygon, int x, int y, int recursionDepth)
    }
    // If the pixel is black and hasn't been visited yet, recursively trace the polygon from that point
    if (brightness(imageMask.get(x + dx, y + dy)) == 0) {
    tracePolygon(polygon, x * imageMask.width, y * imageMask.height, 0);
    tracePolygon(polygon, x + dx, y + dy, recursionDepth + 1);
    }
    }
    }
  21. radiovisual revised this gist Jan 2, 2023. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion processing.pde
    Original file line number Diff line number Diff line change
    @@ -96,7 +96,7 @@ void tracePolygon(ArrayList<PVector> polygon, int x, int y, int recursionDepth)
    }
    // If the pixel is black and hasn't been visited yet, recursively trace the polygon from that point
    if (brightness(imageMask.get(x + dx, y + dy)) == 0) {
    tracePolygon(polygon, x + dx, y + dy, recursionDepth + 1);
    tracePolygon(polygon, x * imageMask.width, y * imageMask.height, 0);
    }
    }
    }
  22. radiovisual revised this gist Jan 2, 2023. 1 changed file with 0 additions and 38 deletions.
    38 changes: 0 additions & 38 deletions processing.pde
    Original file line number Diff line number Diff line change
    @@ -70,44 +70,6 @@ void smoothPolygons() {
    }
    }

    /**
    Second, the tracePolygon() function is not correctly following the outline of the black lines in the image mask. It is only checking the pixels immediately surrounding the current point, which may not always be part of the same line.
    To fix this, you can use a more sophisticated algorithm to trace the outline of the black lines. One option is the "seed fill" algorithm, which works by starting at a point inside a region and following the outline of the region until it reaches the starting point again.
    Here's how you can modify the tracePolygon() function to use the seed fill algorithm:
    // Function to trace the outline of a polygon
    void tracePolygon(ArrayList<PVector> polygon, int x, int y, int recursionDepth) {
    // Check the recursion depth
    if (recursionDepth > maxRecursionDepth) {
    return;
    }
    // Add the current point to the polygon if it hasn't already been visited
    if (brightness(imageMask.get(x, y)) == 0) {
    polygon.add(new PVector(x, y));
    // Set the current pixel to white to mark it as visited
    imageMask.set(x, y, color(255));
    }
    // Check the pixels around the current point
    for (int dx = -1; dx <= 1; dx++) {
    for (int dy = -1; dy <= 1; dy++) {
    // Skip the current point and pixels outside the image
    if (dx == 0 && dy == 0 || x + dx < 0 || x + dx >= imageMask.width || y + dy < 0 || y + dy >= imageMask.height) {
    continue;
    }
    // If the pixel is black, recursively trace the polygon from that point
    if (brightness(imageMask.get(x + dx, y + dy)) == 0) {
    tracePolygon(polygon, x +
    */

    // Maximum recursion depth
    int maxRecursionDepth = 1000;

  23. radiovisual revised this gist Jan 2, 2023. 1 changed file with 41 additions and 1 deletion.
    42 changes: 41 additions & 1 deletion processing.pde
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,6 @@
    PImage imageMask;
    ArrayList<ArrayList<PVector>> polygons;

    void setup() {
    size(512, 512);
    imageMask = loadImage("imageMask.png");
    @@ -11,7 +12,7 @@ void setup() {
    for (int y = 0; y < imageMask.height; y++) {
    for (int x = 0; x < imageMask.width; x++) {
    // If the pixel is black and hasn't been visited yet, start a new polygon and add it to the polygons array
    if (brightness(imageMask.get(x, y)) == 0 && brightness(imageMask.get(x, y)) != 255) {
    if (brightness(imageMask.get(x, y)) == 0) {
    ArrayList<PVector> polygon = new ArrayList<PVector>();
    polygons.add(polygon);
    tracePolygon(polygon, x, y, 0);
    @@ -24,6 +25,7 @@ void setup() {
    }



    void draw() {
    background(255);

    @@ -68,6 +70,44 @@ void smoothPolygons() {
    }
    }

    /**
    Second, the tracePolygon() function is not correctly following the outline of the black lines in the image mask. It is only checking the pixels immediately surrounding the current point, which may not always be part of the same line.
    To fix this, you can use a more sophisticated algorithm to trace the outline of the black lines. One option is the "seed fill" algorithm, which works by starting at a point inside a region and following the outline of the region until it reaches the starting point again.
    Here's how you can modify the tracePolygon() function to use the seed fill algorithm:
    // Function to trace the outline of a polygon
    void tracePolygon(ArrayList<PVector> polygon, int x, int y, int recursionDepth) {
    // Check the recursion depth
    if (recursionDepth > maxRecursionDepth) {
    return;
    }
    // Add the current point to the polygon if it hasn't already been visited
    if (brightness(imageMask.get(x, y)) == 0) {
    polygon.add(new PVector(x, y));
    // Set the current pixel to white to mark it as visited
    imageMask.set(x, y, color(255));
    }
    // Check the pixels around the current point
    for (int dx = -1; dx <= 1; dx++) {
    for (int dy = -1; dy <= 1; dy++) {
    // Skip the current point and pixels outside the image
    if (dx == 0 && dy == 0 || x + dx < 0 || x + dx >= imageMask.width || y + dy < 0 || y + dy >= imageMask.height) {
    continue;
    }
    // If the pixel is black, recursively trace the polygon from that point
    if (brightness(imageMask.get(x + dx, y + dy)) == 0) {
    tracePolygon(polygon, x +
    */

    // Maximum recursion depth
    int maxRecursionDepth = 1000;

  24. radiovisual revised this gist Jan 1, 2023. 1 changed file with 3 additions and 4 deletions.
    7 changes: 3 additions & 4 deletions processing.pde
    Original file line number Diff line number Diff line change
    @@ -1,8 +1,7 @@
    PImage imageMask;
    ArrayList<ArrayList<PVector>> polygons;

    void setup() {
    size(800, 800);
    size(512, 512);
    imageMask = loadImage("imageMask.png");

    // Create an empty array to store the polygons
    @@ -12,19 +11,19 @@ void setup() {
    for (int y = 0; y < imageMask.height; y++) {
    for (int x = 0; x < imageMask.width; x++) {
    // If the pixel is black and hasn't been visited yet, start a new polygon and add it to the polygons array
    if (brightness(imageMask.get(x, y)) == 0) {
    if (brightness(imageMask.get(x, y)) == 0 && brightness(imageMask.get(x, y)) != 255) {
    ArrayList<PVector> polygon = new ArrayList<PVector>();
    polygons.add(polygon);
    tracePolygon(polygon, x, y, 0);
    }

    }
    }

    // Smooth the polygon outlines
    smoothPolygons();
    }


    void draw() {
    background(255);

  25. radiovisual revised this gist Jan 1, 2023. 1 changed file with 0 additions and 38 deletions.
    38 changes: 0 additions & 38 deletions processing.pde
    Original file line number Diff line number Diff line change
    @@ -69,44 +69,6 @@ void smoothPolygons() {
    }
    }

    /**
    Second, the tracePolygon() function is not correctly following the outline of the black lines in the image mask. It is only checking the pixels immediately surrounding the current point, which may not always be part of the same line.
    To fix this, you can use a more sophisticated algorithm to trace the outline of the black lines. One option is the "seed fill" algorithm, which works by starting at a point inside a region and following the outline of the region until it reaches the starting point again.
    Here's how you can modify the tracePolygon() function to use the seed fill algorithm:
    // Function to trace the outline of a polygon
    void tracePolygon(ArrayList<PVector> polygon, int x, int y, int recursionDepth) {
    // Check the recursion depth
    if (recursionDepth > maxRecursionDepth) {
    return;
    }
    // Add the current point to the polygon if it hasn't already been visited
    if (brightness(imageMask.get(x, y)) == 0) {
    polygon.add(new PVector(x, y));
    // Set the current pixel to white to mark it as visited
    imageMask.set(x, y, color(255));
    }
    // Check the pixels around the current point
    for (int dx = -1; dx <= 1; dx++) {
    for (int dy = -1; dy <= 1; dy++) {
    // Skip the current point and pixels outside the image
    if (dx == 0 && dy == 0 || x + dx < 0 || x + dx >= imageMask.width || y + dy < 0 || y + dy >= imageMask.height) {
    continue;
    }
    // If the pixel is black, recursively trace the polygon from that point
    if (brightness(imageMask.get(x + dx, y + dy)) == 0) {
    tracePolygon(polygon, x +
    */

    // Maximum recursion depth
    int maxRecursionDepth = 1000;

  26. radiovisual created this gist Jan 1, 2023.
    144 changes: 144 additions & 0 deletions processing.pde
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,144 @@
    PImage imageMask;
    ArrayList<ArrayList<PVector>> polygons;

    void setup() {
    size(800, 800);
    imageMask = loadImage("imageMask.png");

    // Create an empty array to store the polygons
    polygons = new ArrayList<ArrayList<PVector>>();

    // Iterate through each pixel in the image
    for (int y = 0; y < imageMask.height; y++) {
    for (int x = 0; x < imageMask.width; x++) {
    // If the pixel is black and hasn't been visited yet, start a new polygon and add it to the polygons array
    if (brightness(imageMask.get(x, y)) == 0) {
    ArrayList<PVector> polygon = new ArrayList<PVector>();
    polygons.add(polygon);
    tracePolygon(polygon, x, y, 0);
    }

    }
    }

    // Smooth the polygon outlines
    smoothPolygons();
    }

    void draw() {
    background(255);

    // Draw the polygons
    stroke(0);
    strokeWeight(1);
    noFill();
    for (ArrayList<PVector> polygon : polygons) {
    beginShape();
    for (PVector point : polygon) {
    vertex(point.x, point.y);
    }
    endShape(CLOSE);
    }
    }

    // Function to smooth the polygon outlines
    void smoothPolygons() {
    // Iterate through each polygon
    for (ArrayList<PVector> polygon : polygons) {
    // Create a new array to store the smoothed points
    ArrayList<PVector> smoothedPolygon = new ArrayList<PVector>();
    // Iterate through each point in the polygon
    for (int i = 0; i < polygon.size(); i++) {
    PVector p1 = polygon.get(i);
    PVector p2 = polygon.get((i + 1) % polygon.size());
    PVector p3 = polygon.get((i + 2) % polygon.size());
    // Compute the angle between the three points
    float angle = abs(PVector.angleBetween(p2.sub(p1), p3.sub(p2)));
    // If the angle is acute, add the middle point to the smoothed polygon
    if (angle < PI / 2) {
    smoothedPolygon.add(p2);
    } else {
    // If the angle is obtuse, add a new point halfway between the middle point and the point with the smallest distance
    PVector p4 = p2.lerp(dist(p1.x, p1.y, p2.x, p2.y) < dist(p2.x, p2.y, p3.x, p3.y) ? p1 : p3, 0.5);
    smoothedPolygon.add(p4);
    }
    }
    // Replace the original polygon with the smoothed polygon
    polygon.clear();
    polygon.addAll(smoothedPolygon);
    }
    }

    /**
    Second, the tracePolygon() function is not correctly following the outline of the black lines in the image mask. It is only checking the pixels immediately surrounding the current point, which may not always be part of the same line.
    To fix this, you can use a more sophisticated algorithm to trace the outline of the black lines. One option is the "seed fill" algorithm, which works by starting at a point inside a region and following the outline of the region until it reaches the starting point again.
    Here's how you can modify the tracePolygon() function to use the seed fill algorithm:
    // Function to trace the outline of a polygon
    void tracePolygon(ArrayList<PVector> polygon, int x, int y, int recursionDepth) {
    // Check the recursion depth
    if (recursionDepth > maxRecursionDepth) {
    return;
    }
    // Add the current point to the polygon if it hasn't already been visited
    if (brightness(imageMask.get(x, y)) == 0) {
    polygon.add(new PVector(x, y));
    // Set the current pixel to white to mark it as visited
    imageMask.set(x, y, color(255));
    }
    // Check the pixels around the current point
    for (int dx = -1; dx <= 1; dx++) {
    for (int dy = -1; dy <= 1; dy++) {
    // Skip the current point and pixels outside the image
    if (dx == 0 && dy == 0 || x + dx < 0 || x + dx >= imageMask.width || y + dy < 0 || y + dy >= imageMask.height) {
    continue;
    }
    // If the pixel is black, recursively trace the polygon from that point
    if (brightness(imageMask.get(x + dx, y + dy)) == 0) {
    tracePolygon(polygon, x +
    */

    // Maximum recursion depth
    int maxRecursionDepth = 1000;

    // Function to trace the outline of a polygon
    void tracePolygon(ArrayList<PVector> polygon, int x, int y, int recursionDepth) {
    // Check the recursion depth
    if (recursionDepth > maxRecursionDepth) {
    return;
    }

    // Add the current point to the polygon if it hasn't already been visited
    if (brightness(imageMask.get(x, y)) == 0) {
    polygon.add(new PVector(x, y));
    // Set the current pixel to white to mark it as visited
    imageMask.set(x, y, color(255));
    }

    // Check the pixels around the current point
    for (int dx = -1; dx <= 1; dx++) {
    for (int dy = -1; dy <= 1; dy++) {
    // Skip the current point and pixels outside the image
    if (dx == 0 && dy == 0 || x + dx < 0 || x + dx >= imageMask.width || y + dy < 0 || y + dy >= imageMask.height) {
    continue;
    }
    // If the pixel is black and hasn't been visited yet, recursively trace the polygon from that point
    if (brightness(imageMask.get(x + dx, y + dy)) == 0) {
    tracePolygon(polygon, x + dx, y + dy, recursionDepth + 1);
    }
    }
    }
    }