Actually, I’m a bit confused, because you posted a nice animated code, but it has little to do with the pattern poster image. I tried to write a code using parametric functions to draw the pattern but did not succeed. So what I did was using my shape bezier editor code, which imports a b&w image shape and converts and prints it to a bezierVertex shape. The result is the shape below. I added some lines placing the shapes. Placing shapes is really basic, so I hope no-one is going to eat my liver because I posted a code on a homework-tagged topic.
PShape shp1, shp2;
void setup() {
size(730, 710);
background(255);
smooth(4);
shp1 = createShape(PShape.PATH);
shp1.beginShape();
shp1.vertex(406, 23);
shp1.bezierVertex(522, 35, 592, 67, 752, 48);
shp1.bezierVertex(735, 98, 736, 123, 740, 175);
shp1.bezierVertex(743, 226, 769, 277, 780, 342);
shp1.bezierVertex(771, 371, 748, 378, 710, 377);
shp1.bezierVertex(671, 375, 593, 343, 539, 347);
shp1.bezierVertex(518, 354, 499, 362, 506, 373);
shp1.bezierVertex(512, 383, 534, 413, 576, 412);
shp1.bezierVertex(650, 427, 716, 384, 757, 420);
shp1.bezierVertex(777, 509, 759, 597, 771, 643);
shp1.bezierVertex(669, 629, 601, 657, 543, 654);
shp1.bezierVertex(497, 651, 508, 643, 496, 631);
shp1.bezierVertex(489, 609, 510, 569, 505, 522);
shp1.bezierVertex(500, 497, 496, 494, 470, 484);
shp1.bezierVertex(430, 466, 363, 472, 322, 481);
shp1.bezierVertex(280, 489, 251, 509, 222, 534);
shp1.bezierVertex(209, 534, 206, 520, 201, 512);
shp1.bezierVertex(218, 497, 287, 459, 328, 447);
shp1.bezierVertex(368, 434, 400, 430, 443, 438);
shp1.bezierVertex(485, 445, 554, 468, 582, 494);
shp1.bezierVertex(610, 519, 616, 557, 611, 592);
shp1.bezierVertex(637, 569, 627, 549, 634, 531);
shp1.bezierVertex(650, 528, 703, 577, 707, 575);
shp1.bezierVertex(711, 572, 671, 533, 658, 517);
shp1.bezierVertex(697, 515, 710, 473, 707, 470);
shp1.bezierVertex(704, 466, 683, 503, 640, 495);
shp1.bezierVertex(596, 486, 526, 435, 445, 417);
shp1.bezierVertex(390, 407, 335, 430, 312, 435);
shp1.bezierVertex(372, 376, 428, 354, 492, 334);
shp1.bezierVertex(555, 313, 640, 309, 692, 310);
shp1.bezierVertex(677, 289, 667, 286, 638, 279);
shp1.bezierVertex(608, 271, 540, 268, 517, 267);
shp1.bezierVertex(540, 236, 636, 151, 631, 147);
shp1.bezierVertex(625, 142, 527, 210, 482, 240);
shp1.bezierVertex(484, 221, 491, 198, 483, 176);
shp1.bezierVertex(475, 153, 456, 121, 434, 107);
shp1.bezierVertex(446, 186, 426, 244, 401, 295);
shp1.bezierVertex(375, 345, 296, 413, 279, 412);
shp1.bezierVertex(292, 386, 310, 330, 298, 286);
shp1.bezierVertex(275, 202, 216, 177, 206, 143);
shp1.bezierVertex(209, 105, 239, 81, 235, 78);
shp1.bezierVertex(230, 74, 192, 77, 179, 123);
shp1.bezierVertex(158, 123, 113, 77, 110, 81);
shp1.bezierVertex(112, 95, 165, 129, 161, 143);
shp1.bezierVertex(140, 137, 77, 154, 85, 161);
shp1.bezierVertex(130, 161, 172, 161, 204, 183);
shp1.bezierVertex(235, 204, 265, 252, 274, 291);
shp1.bezierVertex(282, 329, 270, 379, 255, 414);
shp1.bezierVertex(240, 470, 197, 486, 182, 498);
shp1.bezierVertex(165, 490, 169, 490, 160, 482);
shp1.bezierVertex(208, 439, 219, 394, 229, 359);
shp1.bezierVertex(238, 323, 225, 290, 216, 271);
shp1.bezierVertex(206, 252, 200, 248, 174, 245);
shp1.bezierVertex(134, 243, 106, 264, 52, 250);
shp1.bezierVertex(34, 237, 18, 237, 14, 214);
shp1.bezierVertex(15, 169, 39, 129, 20, 32);
shp1.bezierVertex(107, 39, 177, 20, 225, 24);
shp1.bezierVertex(273, 27, 290, 36, 308, 51);
shp1.bezierVertex(334, 91, 282, 170, 301, 213);
shp1.bezierVertex(311, 243, 354, 239, 370, 235);
shp1.bezierVertex(385, 230, 393, 216, 392, 186);
shp1.bezierVertex(390, 155, 357, 80, 360, 53);
shp1.bezierVertex(362, 25, 389, 27, 405, 23);
shp1.endShape();
shp2 = createShape(PShape.PATH);
shp2.beginShape();
shp2.vertex(170, 10);
shp2.bezierVertex(247, 12, 284, 122, 287, 155);
shp2.bezierVertex(297, 155, 332, 140, 341, 148);
shp2.bezierVertex(344, 265, 282, 338, 243, 346);
shp2.bezierVertex(223, 340, 209, 336, 189, 328);
shp2.bezierVertex(178, 301, 206, 216, 180, 184);
shp2.bezierVertex(163, 202, 159, 236, 165, 330);
shp2.bezierVertex(144, 336, 129, 345, 108, 348);
shp2.bezierVertex(18, 287, 3, 187, 17, 152);
shp2.bezierVertex(32, 154, 37, 152, 66, 157);
shp2.bezierVertex(83, 58, 113, 42, 169, 10);
shp2.endShape(CLOSE);
shapeMode(CENTER);
fill(0);
circle(width/2+7, height/2, 90);
scale(.5, .45);
shp1.setFill(color(0));
shp2.setFill(color(0));
shapeMode(CENTER);
translate(400,400);
rotate(-HALF_PI);
shape(shp1);
translate(0, 680);
scale(1, -1);
shape(shp1);
translate(-770, 680);
rotate(PI);
shape(shp1);
translate(0, 680);
scale(1, -1);
shape(shp1);
scale(.90);
translate(-430, 80);
shape(shp2);
translate(10, 590);
rotate(PI);
shape(shp2);
translate(340, 290);
rotate(HALF_PI);
scale(.9, 1.2);
shape(shp2);
translate(10,560);
rotate(PI);
shape(shp2);
}
Here is my shape bezier editor code for if you want to draw other shapes.
You’ll need the openCV library installed.
On line 32 you import your b&w bitmap.
Sometimes there are some extra points that result in multiple contours, so you need to set the right one in line 40: Contour contour = contours.get(0); Try from 0 up to the total number of contours printed in the console. You’ll also need to set the width and height of the shape you want on line 13: img.resize(360, 360); This resize will determine the shape size. Just run the sketch and reduce the number of knots using the slider, which almost all the time means totally to the right. Then click edit and drag the green circles to change the curves. The red square knots can also be moved and removed. The latter I do not recommend at the moment because I haven’t included an undo button. Later on, I’ll do that and will modify this post with some improvements needed. To finish just hit the print button and copy the code from the console
import gab.opencv.*;
import java.awt.Point;
import java.util.Queue;
import java.util.LinkedList;
import java.util.*;
float[][] cc = {{210, 168}, {430, 30}, {493, -35}, {410, 10}, {450, -75}, {400, 148}, {292, -75}, {185, 135}, {130, 110}, {180, 216}, {130, 215}, {210, 280}, {70, 185}}; // circle center
float[][] ca = {{-.15, .5}, {.18, .3}, {0.02, .12}, {.22, .35}, {.08, .16}, {.66, 1.56}, {-.29, -.02}, {-.67, -.23}, {-.18, -.08}, {-.54, -.08}, {-.07, .06}, {-.38, 0}, {0, .2}}; // circle arc {start,stop}
int[] radius = {300, 148, 160, 150, 177, 105, 255, 110, 110, 110, 110, 110, 250};
PImage img;
PShape shp1;
ArrayList<PVector> contol1 = new ArrayList<PVector>();
ArrayList<PVector> contol2 = new ArrayList<PVector>();
ArrayList<PVector> anchor1 = new ArrayList<PVector>();
ArrayList<PVector> anchor2 = new ArrayList<PVector>();
ArrayList<PVector> all_points = new ArrayList<PVector>();
ArrayList<PVector> rdp_points = new ArrayList<PVector>();
ArrayList<Contour> contours;
float loc = 15, epsilon = 1, x1, y1, x2, y2, x3, y3, x4, y4;
int control_point, control_index;
boolean curve_mode = true, bezier_mode;
OpenCV ocv;
CurveToBezier c2b = new CurveToBezier();
void setup() {
size(800, 800);
surface.setTitle("Bezier edit");
img = loadImage("pattern2.png");
img.resize(360, 360);
filter(INVERT);
ocv = new OpenCV(this, img);
contours = ocv.findContours();
println("number of contours = "+contours.size()); // Cheque if you have more then 1 !
// Bitmap created by parametric function above has 2 contours so be sure to selct the right one here.
Contour contour = contours.get(0);
for (PVector point : contour.getPoints()) {
point(point.x, point.y);
all_points.add(new PVector(point.x, point.y));
}
textSize(18);
}
void draw() {
background(255);
stroke(220, 220, 255);
strokeWeight(4);
noFill();
beginShape();
for (PVector v : all_points) {
vertex(v.x, v.y);
}
endShape();
if (curve_mode) {
rdp_points = new ArrayList<PVector>();
int total = all_points.size();
PVector start = all_points.get(0);
PVector end = all_points.get(total-1);
rdp_points.add(start);
rdp(0, total-1, all_points, rdp_points);
rdp_points.add(end);
stroke(0);
strokeWeight(1);
beginShape();
PVector v1 = new PVector();
v1 = rdp_points.get(rdp_points.size()-1);
curveVertex(v1.x, v1.y);
for (PVector v : rdp_points) {
curveVertex(v.x, v.y);
fill(255, 0, 0);
ellipse(v.x, v.y, 5, 5);
}
PVector v2 = new PVector();
v2 = rdp_points.get(0);
curveVertex(v2.x, v2.y);
noFill();
endShape();
fill(0);
text("epsilon: " + nf(epsilon, 2, 2), 150, 80);
text("Total Points: " + (rdp_points.size()-1), 50, 50);
drawSlider();
fill(0);
text("Edit", 510, 430);
} else if (bezier_mode) {
fill(0);
text("Total Points: "+(contol1.size()), 50, 50);
stroke(0);
strokeWeight(1);
beginShape();
vertex(rdp_points.get(1).x, rdp_points.get(1).y);
for (int i = 0; i < anchor2.size(); i++) {
x1 = anchor1.get(i).x;
y1 = anchor1.get(i).y;
x2 = contol1.get(i).x;
y2 = contol1.get(i).y;
x3 = contol2.get(i).x;
y3 = contol2.get(i).y;
x4 = anchor2.get(i).x;
y4 = anchor2.get(i).y;
fill(0, 255, 255);
circle(contol1.get(i).x, contol1.get(i).y, 8);
circle(contol2.get(i).x, contol2.get(i).y, 8);
stroke(150);
line(x4, y4, x3, y3);
line(x2, y2, x1, y1);
stroke(0);
fill(255, 130, 130);
circle(rdp_points.get(0).x, rdp_points.get(0).y, 7);
circle(anchor1.get(i).x, anchor1.get(i).y, 7);
circle(anchor2.get(i).x, anchor2.get(i).y, 7);
noFill();
bezierVertex(x2, y2, x3, y3, x4, y4);
}
endShape();
drawSlider();
fill(0);
text("Print", 510, 430);
}
noFill();
strokeWeight(1.3);
rect(490, 410, 80, 28);
}
void mousePressed() {
if (mouseX > 530 && mouseY < 50) {
println();
}
if (curve_mode) {
if (mouseX > 490 && mouseY > 410 && mouseY < 438) {
rdp_points.add(0, rdp_points.get(0));
rdp_points.add(rdp_points.get(0));
for (int i = 0; i < rdp_points.size(); i++) {
c2b.makeBezierVertex(rdp_points.get(i).x, rdp_points.get(i).y);
}
for (int i = 1; i < rdp_points.size(); i++) {
anchor1.add(new PVector(rdp_points.get(i).x, rdp_points.get(i).y));
}
curve_mode = false;
bezier_mode = true;
}
} else if (bezier_mode ) {
for (int i = 0; i < contol1.size(); i++) {
if (mouseX < contol1.get(i).x+6 && mouseX > contol1.get(i).x-6 &&
mouseY < contol1.get(i).y+6 && mouseY > contol1.get(i).y-6) {
control_point = 1;
control_index = i;
}
if (mouseX < contol2.get(i).x+6 && mouseX > contol2.get(i).x-6 &&
mouseY < contol2.get(i).y+6 && mouseY > contol2.get(i).y-6) {
control_point = 2;
control_index = i;
}
if (mouseX < anchor2.get(i).x+6 && mouseX > anchor2.get(i).x-6 &&
mouseY < anchor2.get(i).y+6 && mouseY > anchor2.get(i).y-6) {
control_point = 3;
control_index = i;
if (mouseButton == RIGHT && i != anchor2.size()-1) {
anchor1.remove(i+1);
anchor2.remove(i);
contol1.remove(i);
contol2.remove(i);
}
}
}
if (mouseX > 490 && mouseY > 410 && mouseY < 438) {
println();
println("shp2 = createShape(PShape.PATH);");
println("shp2.beginShape();");
println("shp2.vertex("+int(rdp_points.get(1).x)+", "+int(rdp_points.get(1).y)+");");
for (int i = 0; i < contol2.size(); i++) {
x1 = anchor1.get(i).x;
y1 = anchor1.get(i).y;
x2 = contol1.get(i).x;
y2 = contol1.get(i).y;
x3 = contol2.get(i).x;
y3 = contol2.get(i).y;
x4 = anchor2.get(i).x;
y4 = anchor2.get(i).y;
println("shp2.bezierVertex("+int(x2)+", "+int(y2)+", "+int(x3)+", "+int(y3)+", "+int(x4)+", "+int(y4)+");");
}
println("shp2.endShape();");
}
}
}
void mouseDragged() {
if (curve_mode) {
loc = mouseX;
if (loc < 15) loc = 15;
if (loc > width-15) loc = width-15;
epsilon = int(map(loc-10.55, 0.0, width, 1.0, 17.0));
} else if (bezier_mode) {
if (control_point == 1) contol1.set(control_index, new PVector(mouseX, mouseY));
if (control_point == 2) contol2.set(control_index, new PVector(mouseX, mouseY));
if (control_point == 3 && control_index < anchor2.size()-1) {
anchor2.set(control_index, new PVector(mouseX, mouseY));
anchor1.set(control_index+1, new PVector(mouseX, mouseY));
float tx1 = contol1.get(control_index+1).x;
float ty1 = contol1.get(control_index+1).y;
float tx2 = contol2.get(control_index).x;
float ty2 = contol2.get(control_index).y;
contol1.set(control_index+1, new PVector(tx1+(mouseX-pmouseX), ty1+(mouseY-pmouseY)));
contol2.set(control_index, new PVector(tx2+(mouseX-pmouseX), ty2+(mouseY-pmouseY)));
}
}
}
void rdp(int start_index, int end_index, ArrayList<PVector> all_points, ArrayList<PVector> rdp_points) {
int next_index = findFurthest(all_points, start_index, end_index);
if (next_index > 0) {
if (start_index != next_index) {
rdp(start_index, next_index, all_points, rdp_points);
}
rdp_points.add(all_points.get(next_index));
if (end_index != next_index) {
rdp(next_index, end_index, all_points, rdp_points);
}
}
}
int findFurthest(ArrayList<PVector> points, int a, int b) {
float record_distance = -1;
PVector start = points.get(a);
PVector end = points.get(b);
int furthest_index = -1;
for (int i = a+1; i < b; i++) {
PVector current_point = points.get(i);
float d = lineDist(current_point, start, end);
if (d > record_distance) {
record_distance = d;
furthest_index = i;
}
}
if (record_distance > epsilon) {
return furthest_index;
} else {
return -1;
}
}
float lineDist(PVector c, PVector a, PVector b) {
PVector norm = scalarProjection(c, a, b);
return PVector.dist(c, norm);
}
PVector scalarProjection(PVector p, PVector a, PVector b) {
PVector ap = PVector.sub(p, a);
PVector ab = PVector.sub(b, a);
ab.normalize(); // Normalize the line
ab.mult(ap.dot(ab));
PVector normal_point = PVector.add(a, ab);
return normal_point;
}
void drawShapeBorder() {
float step = 2*PI/60;
float px = 0, py = 0;
for (int i = 0; i < 13; i++) {
push();
translate(cc[i][0], cc[i][1]);
int j = 0;
for (float t = ca[i][0]*PI; t < ca[i][1]*PI+step; t += step) {
float x = radius[i]*sin(t);
float y = radius[i]*cos(t);
if (j == 0) {
px = x;
py = y;
}
line(x, y, px, py);
px = x;
py = y;
j++;
}
pop();
}
}
void fillShape() {
img = get();
img.loadPixels();
Queue<Point> queue = new LinkedList<Point>();
queue.add(new Point(width/2, height/2));
while (!queue.isEmpty()) {
Point p = queue.remove();
if (check(p.x, p.y)) {
queue.add(new Point(p.x, p.y-1));
queue.add(new Point(p.x, p.y+1));
queue.add(new Point(p.x-1, p.y));
queue.add(new Point(p.x+1, p.y));
}
}
img.updatePixels();
}
boolean check(int x, int y) {
if (x < 0 || y < 0 || y >= img.height || x >= img.width) return false;
int pp = img.pixels[x+(y*img.width)];
if (pp != color(0)) return false;
img.pixels[x + (y * img.width)] = color(255);
return true;
}
void drawSlider() {
push();
noStroke();
fill(255);
rect(0, height-30, width, 30);
fill(200, 200, 255);
rect(10, height-15, width-20, 5);
fill(150, 150, 255);
ellipse(loc, height-13, 15, 15);
pop();
}
class CurveToBezier {
private PVector ring[] = new PVector[4];
private int count = 0;
CurveToBezier() {
ring[0] = new PVector();
ring[1] = new PVector();
ring[2] = new PVector();
ring[3] = new PVector();
}
void makeBezierVertex(float x, float y) {
ring[count % 4].x = x;
ring[count % 4].y = y;
if (count >= 3) makeBezierZero(ring[(count-3)%4], ring[(count-2)%4], ring[(count-1)%4], ring[count%4]);
count++;
}
private void makeBezierZero(PVector c0, PVector c1, PVector c2, PVector c3) {
PVector b1 = new PVector(0, 0);
PVector b2 = new PVector(0, 0);
b1.add(c2);
b1.sub(c0);
b1.add(PVector.mult(c1, 6));
b1.div(6);
b2.add(c1);
b2.sub(c3);
b2.add(PVector.mult(c2, 6));
b2.div(6);
contol1.add(b1);
contol2.add(b2);
anchor2.add(new PVector(c2.x, c2.y));
}
}