Antony's Blog

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:

  1. 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
  2. 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.
  3. 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.
  4. 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