Enjoy the 'Truchet Tiling' with your own patterns.

Truchet Tiling of my own design.

'Truchet Tiling' is the way that makes you create some interesting patterns with the simple design and the simple algorithm.

In this article, I'll start with 'What is the Truchet Tiling' and show you how to make the tile design. And also, I'll show you the example code to draw the pattern.

Let's enjoy 'Truchet Tiling' with your own design using the p5.js and the Processing.

👉 この記事は日本語でも読めます。

 

What is the Truchet tiling or Truchet pattern?

The 'Truchet Tiling' is the pattern made with the 'Truchet Tile'. And the 'Truchet Tile' is the square tile that is not rotationally symmetric.

Wikipedia : Truchet tiles

Let me explain with concrete examples. You might have seen a picture like this.

Common Truchet Tiling.

This is the 10 x 10 matrix tiling.

Common Truchet Tiling in matrix.

The 'Truchet Tile' used in this picture is 'A'. And the 'B' is 90 degrees rotated 'A'.

One piece of Truchet Tile.

This picture is made with just one kind of tile rotating 90 degrees randomly.

Common Truchet Tiling.32 x 32

 

Here is the example code of the 'Truchet Tiling' with p5.js.


/*
 * Truchet Tiling example code.
 * p5.js
 * @author @deconbatch
 * @version 0.1
 * created 2022.02.28
 * license CC0
 */

const w = 640;
const h = w;
const num = 10;

function setup() {
  createCanvas(w, h);
  imageMode(CENTER);

  const cell = getPattern(floor(w / num));

  background(224);
  for (let x = 0; x < num; x++) {
    for (let y = 0; y < num; y++) {
      push();
      translate((x + 0.5) * w / num, (y + 0.5) * height / num);
      if (random(1.0) < 0.5) {
        rotate(HALF_PI);
      }
      image(cell, 0, 0);
      pop();
    }
  }
}

function getPattern(_size) {
  g = createGraphics(_size, _size);
  g.background(224);
  g.noFill();
  g.stroke(96);
  g.strokeWeight(_size * 0.1);
  g.circle(0, 0, _size);
  g.circle(_size, _size, _size);
  return g;
}

 







How to design the tile of Truchet tiling?

It's fun and a little thrilling to make some interesting patterns with the simply designed tile. It's must be more fun to use your own designed tile.

By definition, the tile design that is not rotationally symmetric is correct.

Truchet Tile, not so good.

But it's not enough for making an interesting pattern. It often disconnect the lines in pattern.

Truchet Tiling that disconnected the lines in pattern.

 

You should make the design that the connection points on four sides connect when it rotates to make the lines in the pattern will not disconnect.

Truchet Tile, nice design.

Truchet Tiling with nice design.

 

1.Plot the connection points on one side.

Points on one side.

2.Copy it to the rest three sides rotating 90 degrees.

Copy the point to the rest three sides.

3.Copy it upside-down or left-to-right.

Copy points upside-down.

Then draw the lines between the connection points. Be aware it must not be rotationally symmetric. I drew lines by the hand like this by way of trial.

Hand drawn Truchet tile.

And I made a pattern with it.

Truchet tiling with Hand drawn tile.

 

Let's play with the tile of your own design.

You can make a pattern with the tile of your own design using the example code I showed before. All you need to do is change the 'getPattern()' function.

If you want to use hand drawn designed tile, you can use the 'loadImage()' not 'getPattern()' function. Don't forget to resize the tile image to fit the size of the cell.

For example.


let img;
function preload() {
  img = loadImage('ptn.jpg');
}

function setup() {
  createCanvas(w, h);
  imageMode(CENTER);

  const cell = img.resize(floor(w / num), floor(w / num));


 







Example source code of the 'Processing'.

Truchet tiling with 'bezier()' function.

I designed the tile with the 'bezier()' function in this example work. And I used upside-down and left-to-right turns, not rotation. That's because the rotation sometimes creates the gap when the center axis shifts.

Gap created between tiles.

Please feel free to use this example code under the terms of the GPL. To see other works based on my code is my pleasure. And my honor.


/**
 * Magic Carpet Ride.
 * auto pattern generated Truchet Tiling.
 * 
 * @author @deconbatch
 * @version 0.1
 * @license GPL Version 3 http://www.gnu.org/licenses/
 * Processing 3.5.3
 * 2022.02.20
 */

void setup() {

  size(900, 900);
  colorMode(HSB, 360, 100, 100, 100);
  imageMode(CENTER);

  int   frmMax  = 3;
  int   divBase = 15;
  int   start   = floor(random(frmMax));
  float hueBase = random(360.0);

  for (int frmCnt = 0; frmCnt < frmMax; frmCnt++) {

    int div = divBase + ((start + frmCnt) % frmMax) * 5;
    float hueVal = hueBase + frmCnt * 120.0;

    PImage cell = getPattern(floor(width / div), hueVal);
    background(hueVal % 360.0, 5.0, 80.0, 100.0);
    for (int x = 0; x < div; x++) {
      for (int y = 0; y < div; y++) {
        pushMatrix();
        translate((x + 0.5) * width * 1.0 / div, (y + 0.5) * height * 1.0 / div);
        //  rotate(floor(random(4.0)) * HALF_PI);
        if (random(1.0) < 0.5) {
          scale(-1.0, 1.0);
        }
        if (random(1.0) < 0.5) {
          scale(1.0, -1.0);
        }
        image(cell, 0, 0);
        popMatrix();
      }
    }

    casing(100);
    saveFrame("frames/" + String.format("%04d", frmCnt + 1) + ".png");

  }
  
  exit();
  
}

/** 
 * getPattern : returns random generated pattern
 */
PImage getPattern(int _size, float _hue) {
  // connect points
  PVector[][] points = {
    {new PVector(0.0, 0.5), new PVector(0.5, 1.0)},
    {new PVector(0.5, 0.0), new PVector(1.0, 0.5)},
    {new PVector(0.0, 0.25), new PVector(0.25, 0.0)},
    {new PVector(0.75, 1.0), new PVector(1.0, 0.75)},
    {new PVector(0.75, 0.0), new PVector(1.0, 0.25)},
    {new PVector(0.0, 0.75), new PVector(0.25, 1.0)},
  };
  int pNum = points.length;

  PGraphics g = createGraphics(_size, _size);

  g.beginDraw();
  g.colorMode(HSB, 360, 100, 100, 100);
  g.blendMode(BLEND);
  g.background(_hue % 360.0, 5.0, 80.0, 100.0);
  g.noStroke();
  for (int i = 0; i < pNum; i++) {
    PVector[] p = points[i];
    float hueVal = (_hue + i * 30.0) % 360;
    float pRnd = random(0.1, 0.9);
    g.fill(hueVal, 40, 60, 100);
    g.bezier(
             p[0].x * _size, p[0].y * _size,
             pRnd * _size, pRnd * _size,
             (1.0 - pRnd) * _size, (1.0 - pRnd) * _size,
             p[1].x * _size, p[1].y * _size
             );
  }
  g.endDraw();

  return g;

}

/**
 * casing : draw fancy casing
 */
public void casing(int _m) {
  fill(0.0, 0.0);

  strokeWeight(_m * 2 - 10.0);
  stroke(0.0, 0.0, 95.0, 100.0);
  rect(0.0, 0.0, width, height);

  strokeWeight(_m * 2 - 32.0);
  stroke(0.0, 0.0, 80.0, 100.0);
  rect(0.0, 0.0, width, height);

  strokeWeight(20.0);
  stroke(0.0, 0.0, 50.0, 100.0);
  rect(0.0, 0.0, width, height);

  strokeWeight(16.0);
  stroke(0.0, 0.0, 100.0, 100.0);
  rect(0.0, 0.0, width, height);
}

 

Next Post Previous Post
No Comment
Add Comment
comment url