Marching Squares (Coding Train Inspiration)
July 27, 2020
Marching Squares algorithm and Endless MAPS
5th week of blogging
Hai,Everyone 👋 ,
When watching Youtube, Coding Train Channel go my Eyes, the video was ” Coding in the Cabana, Gloria Pickle and I investigate the Marching Squares algorithm and apply it to Open Simplex Noise in Processing. ”
I liked the video and made my mind to implement it, but the problem was that I don’t know p5js.
“p5.js is a JavaScript library for creative coding, with a focus on making coding accessible and inclusive for artists, designers, educators, beginners, and anyone else! p5.js is free and open-source because we believe software, and the tools to learn it, should be accessible to everyone. ~According to https://p5js.org/”
Then I got an idea, why can’t we put this in angular
so I did it. Angular+p5js
The problem is that of communication between p5js and typescript. After so much of searching, I got a method that worked put sketch in ngOnInit()
const sketch = (s) => {
s.preload = () => {
}
s.setup = () => {
}
s.draw = () => {
}
}
this.canvas = new p5(sketch);
}
Now let’s do the Marching Squares algorithm:
constructor() {
this.getScreenSize();
}
@HostListener('window:resize', ['$event'])
getScreenSize(event?) {
this.screenHeight = window.innerHeight;
this.screenWidth = window.innerWidth;
console.log(this.screenHeight, this.screenWidth);
}
getRandomInt(max) {
return Math.floor(Math.random() * Math.floor(max));
}
getState(a, b, c, d) {
return a * 8 + b * 4 + c * 2 + d * 1;
}
ngOnInit() {
let res = 30;
let col,row;
let weigth = res / 3.5;
const sketch = (s) => {
s.preload = () => {
}
const drawLine = (v1, v2) => {
s.line(v1.x, v1.y, v2.x, v2.y);
}
const fill = () => {
for (let i = 0; i <= col; i++) {
let k = [];
for (let j = 0; j <= row; j++) {
k.push(0);
}
this.field.push(k);
}
for(let i=0;i <= col;i++){
for(let j=0;j <= row;j++){
this.field[i][j] = Math.floor(this.getRandomInt(2));
}
}
}
s.setup = () => {
let p = s.createCanvas(this.screenWidth, this.screenHeight - 100);
p.parent('sketch-holder');
col = 1 + Math.floor(this.screenWidth / res);
row = 1 + Math.floor(this.screenHeight / res);
this.field = [];
fill();
}
s.draw = () => {
s.background(0, 0, 255);
s.stroke(235, 143, 52);
s.strokeWeight(weigth);
s.fill(0, 0, 255)
s.rect(0,0,this.screenWidth, this.screenHeight - 100)
for(let i=0;i < col;i++){
for(let j=0;j< row;j++){
let x = i * res;
let y = j * res;
let a = s.createVector(x + res * 0.5, y);
let b = s.createVector(x + res, y + res * 0.5);
let c = s.createVector(x + res * 0.5, y + res);
let d = s.createVector(x, y + res * 0.5);
let state = this.getState(
s.ceil(this.field[i][j]),
s.ceil(this.field[i + 1][j]),
s.ceil(this.field[i + 1][j + 1]),
s.ceil(this.field[i][j + 1])
);
s.stroke(235, 143, 52);
s.strokeWeight(weigth);
switch (state) {
case 1:
drawLine(c, d);
break;
case 2:
drawLine(b, c);
break;
case 3:
drawLine(b, d);
break;
case 4:
drawLine(a, b);
break;
case 5:
drawLine(a, d);
drawLine(b, c);
break;
case 6:
drawLine(a, c);
break;
case 7:
drawLine(a, d);
break;
case 8:
drawLine(a, d);
break;
case 9:
drawLine(a, c);
break;
case 10:
drawLine(a, b);
drawLine(c, d);
break;
case 11:
drawLine(a, b);
break;
case 12:
drawLine(b, d);
break;
case 13:
drawLine(b, c);
break;
case 14:
drawLine(c, d);
break;
}
}
}
}//draw
s.mouseDragged = () => {
fill();
}
s.mouseReleased = () => {
fill();
}
}
this.canvas = new p5(sketch);
}
The Purpose of the Marching Squares algorithm is to generate contours. Steps of the algorithm:
- We divide the screen into columns and rows so that each col and row forms squares whose vertices can be white or dark in the case for implementation we use 0,1
- We compute the midpoints of all the edges so that, if there are 2, 0/white adjoined we can draw a line between those. Since there 16 possibilities in case of joining the midpoints for the squares.
- We use the Binay to decimal conversion to convert 4 digit binary represents to decimal hence we can draw the corresponding line between the midpoints.
- When a whole lot of squares join together, it forms contours.
Which I used to create a MAP whenever the user clicks or drags the mouse. Endless Map