0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Truchetタイル

Last updated at Posted at 2024-10-07

本記事は、以下の記事から続いています。

Truchet トルシェット タイル

正方形を斜めに分け、白黒に塗り分けたタイルを用意する。これを敷き詰める際に向きをランダムにしたり、規則的にすることで、また別の模様が見えてくる。

truchet.png

int(random(4))*90;

乱数0~3.999を発生させ、intで整数に切り捨てる(0,1,2,3)。
その後90を掛けて、0,90,180,270を生成する。

radians(th);

度をラジアンに単位変換する命令。

PImage img;

size(640, 640);
img = loadImage("truchet.png");

for (int y=0; y<640; y+=64) {
  for (int x=0; x<640; x+=64) {
    float th = int(random(4))*90;
    push();
      translate(x+32, y+32);
      rotate(radians(th));
      translate(-img.width/2, -img.height/2);
      image(img, 0, 0);
    pop();
  }
}

image.png

六角形充填

 正方形と同様に、六角形を敷き詰める事を考える。
 画像は、イラレから書き出す際に、背景を透過色pngで保存する。
 画像サイズは、64x64として、画像の中心が六角形の中心になるようにする。
truchetHex.png

int(random(6))*60

これは0,60,120,180,240,300を生成する式である。

((x/(int)w)%2*(h*0.5))

これは、xをwで割ったときに、奇数か偶数かで、上下にずらす値を計算する式である。
xを整数で割りたいので、intでwを変換し、
%2で、余りが、0か1を求める。
その結果に、ずらしたい縦の移動量(h*0.5)を掛けている。
h/2だと結果が、整数になるかもしれないので、避けている。

「55.4256」この値は、イラレで表示された値です。

PImage img;

float w=64-16;
float h=55.4256;

size(640, 640);
img = loadImage("truchetHex.png");

for (int y=0; y<640; y+=h) {
  for (int x=0; x<640; x+=w) {
    float th = int(random(6))*60;
    push();
      translate(x, y+((x/(int)w)%2*(h*0.5)));
      rotate(radians(th));
      translate(-img.width/2, -img.height/2);
      image(img, 0, 0);
    pop();
  }
}

image.png

改良

truchetパターンは多く考案されているので、正方形や六角形の画像を差し替えて、違うバリエーションを試してほしい。

スクショを撮るか、save("xxx.png");で保存提出。

おまけ

我が家の、なんかしらん袋
IMG_6283.jpeg

おまけ2、AIにプログラムを依頼

// Truchet Aesthetic Playground
// Processing (Java) 3.x/4.x

int tile = 64;          // タイルサイズ
int style = 1;          // 1..6
int paletteId = 0;      // 0..3
boolean showGrid = false;
boolean mirrorSym = false; // ミラー対称ON/OFF
boolean showHelp = true;
float sw = 3.0;         // 線幅
int seedBase = (int)random(1<<30);

void setup() {
  size(960, 960);
  smooth(8);
  frameRate(60);
  reseed();
}

void reseed() {
  seedBase = (int)random(1<<30);
  randomSeed(seedBase);
  noiseSeed(seedBase);
  redraw();
}

void draw() {
  background(bgColor());
  strokeWeight(sw);
  noFill();
  
  int cols = ceil(width / (float)tile);
  int rows = ceil(height / (float)tile);
  
  // 中心を基準にノイズの位相
  float t = millis()*0.0003; // わずかにアニメ的な“呼吸”もOKに(止めたい時はt=0に)
  
  for (int j = 0; j < rows; j++) {
    for (int i = 0; i < cols; i++) {
      pushMatrix();
      translate(i*tile, j*tile);
      
      int rot = pickRotation(i, j, t); // 0,1,2,3 のいずれか
      // ミラー対称(左右/上下)を入れると“柄としてのまとまり”が出る
      if (mirrorSym) {
        int mi = min(i, cols-1-i);
        int mj = min(j, rows-1-j);
        rot = pickRotation(mi, mj, t);
      }
      
      // タイルごとに色を切り替える(パレットと連動)
      stroke(colLine(i, j));
      
      // 中心回転しやすいようにローカル座標へ
      translate(tile*0.5, tile*0.5);
      rotate(HALF_PI * rot);
      translate(-tile*0.5, -tile*0.5);
      
      // 選択スタイル
      switch(style) {
        case 1: drawQuarterArcs(); break;     // 定番:四分円
        case 2: drawDiagonalCurves(); break;  // 対角を結ぶ曲線(エレガント)
        case 3: drawTriCuts(); break;         // 三角分割+反転(幾何学的)
        case 4: drawHatchLines(); break;      // ハッチング線(密度差)
        case 5: drawRibbon(); break;          // リボン状ベジェ(柔らかさ)
        case 6: drawDots(); break;            // ドット接続(軽やか)
      }
      
      if (showGrid) {
        stroke(0, 30);
        noFill();
        rect(0, 0, tile, tile);
      }
      popMatrix();
    }
  }
  
  if (showHelp) drawHUD();
}

// ==== タイル描画バリエーション ====

// 1) Truchet定番:四分円(角Rを大きめに)
void drawQuarterArcs() {
  float r = tile;
  strokeCap(SQUARE);
  arc(0, 0, r, r, 0, HALF_PI);
  arc(tile, tile, r, r, PI, PI+HALF_PI);
}

// 2) 対角を結ぶ曲線(近接端をC曲線で繋ぐ)
void drawDiagonalCurves() {
  strokeCap(ROUND);
  float m = tile*0.15;
  // 左上→右下
  beginShape();
  vertex(0, m);
  quadraticVertex(tile*0.5, tile*0.5, tile-m, tile);
  endShape();
  // 左下→右上(対称にもう1本)
  beginShape();
  vertex(m, tile);
  quadraticVertex(tile*0.5, tile*0.5, tile, m);
  endShape();
}

// 3) 三角分割+反転(陰影=線の太さ差で)
void drawTriCuts() {
  pushStyle();
  float m = tile*0.08;
  strokeWeight(sw*0.9);
  line(0, 0, tile, tile);
  strokeWeight(sw*0.45);
  line(0, tile, tile, 0);
  // 端に少し“返し”
  strokeWeight(sw*0.7);
  line(m, 0, m, tile);
  popStyle();
}

// 4) ハッチング(密度差で模様感)
void drawHatchLines() {
  pushStyle();
  float step = tile/8.0;
  for (float y=0; y<=tile; y+=step) {
    line(0, y, tile, y);
  }
  // 反対方向に薄く
  stroke(0, 60);
  for (float x=0; x<=tile; x+=step*2.0) {
    line(x, 0, x, tile);
  }
  popStyle();
}

// 5) リボン状ベジェ(端点と接線方向を揃える)
void drawRibbon() {
  pushStyle();
  noFill();
  float k = tile*0.25;
  float inset = tile*0.12;
  // 太線→細線で奥行き感
  strokeWeight(sw*1.1);
  drawRibbonCore(inset, k);
  strokeWeight(sw*0.6);
  drawRibbonCore(inset*1.5, k*0.9);
  popStyle();
}

void drawRibbonCore(float inset, float k) {
  beginShape();
  vertex(inset, inset);
  bezierVertex(tile*0.5, inset-k, tile-inset+k, tile*0.5, tile-inset, tile-inset);
  endShape();
}

// 6) ドット接続(モアレを避けつつ軽やか)
void drawDots() {
  float s = tile/6.0;
  float r = max(1.2, sw*0.55);
  for (int y=0; y<6; y++) {
    for (int x=0; x<6; x++) {
      if ( (x+y)%2==0 ) {
        ellipse((x+0.5)*s, (y+0.5)*s, r, r);
      }
    }
  }
}

// ==== 配色(落ち着き/華やかを切替) ====
int bgColor() {
  switch (paletteId) {
    case 0: return color(246, 245, 240);  // 生成り
    case 1: return color(9, 13, 20);      // 墨
    case 2: return color(252, 249, 244);  // 和紙
    default:return color(244, 248, 252);  // 淡い青
  }
}
int colLine(int i, int j) {
  // 行列の偶奇+ノイズでうっすら揺らぎ
  float n = noise(i*0.17, j*0.17);
  switch (paletteId) {
    case 0: { // 紺・朱・生成り
      color[] cs = { color(23, 43, 77), color(186, 62, 38), color(64, 112, 153) };
      return lerpColor(cs[(i+j)%3], color(0,0,0), 0.05 + 0.2*n);
    }
    case 1: { // 墨背景用:藍〜薄灰
      color[] cs = { color(179, 196, 219), color(118, 150, 188), color(210, 216, 226) };
      return lerpColor(cs[(i+j)%3], color(255), 0.15*n);
    }
    case 2: { // 萌黄色・山吹
      color[] cs = { color(21, 101, 112), color(234, 146, 37), color(160, 77, 58) };
      return lerpColor(cs[(i+j)%3], color(30), 0.1*n);
    }
    default: { // 北欧っぽい淡配色
      color[] cs = { color(33, 86, 117), color(235, 87, 87), color(244, 210, 74) };
      return lerpColor(cs[(i+j)%3], color(20), 0.1*n);
    }
  }
}

// ==== 回転選択(“離散化されたランダム”) ====
// 0/90/180/270°を、ノイズと偶奇でバランス良く配る
int pickRotation(int i, int j, float t) {
  float k = 0.23;
  float n = noise(i*k, j*k, t*0.35); // 0..1
  // 偶奇で“地合い”を作る
  int base = ((i+j)&1)==0 ? 0 : 2;
  // ノイズで近傍の連続性をもたせつつ離散化
  int r = base + floor(constrain(map(n, 0, 1, 0, 2.999), 0, 3));
  return r % 4;
}

// ==== UI / 入出力 ====
void keyPressed() {
  if (key>='1' && key<='6') { style = key - '0'; redraw(); }
  if (key=='r' || key=='R') { reseed(); }
  if (key=='p' || key=='P') { paletteId = (paletteId+1)%4; redraw(); }
  if (key=='g' || key=='G') { showGrid = !showGrid; redraw(); }
  if (key=='m' || key=='M') { mirrorSym = !mirrorSym; redraw(); }
  if (key=='h' || key=='H') { showHelp = !showHelp; }
  if (key=='[') { tile = max(24, tile-8); redraw(); }
  if (key==']') { tile = min(160, tile+8); redraw(); }
  if (key==',') { sw = max(0.5, sw-0.5); redraw(); }
  if (key=='.') { sw = min(12,  sw+0.5); redraw(); }
  if (key=='s' || key=='S') {
    String fn = String.format("truchet_%d_style%d_pal%d.png", seedBase, style, paletteId);
    save(fn);
    println("saved:", fn);
  }
}

void drawHUD() {
  pushStyle();
  fill(0, 150);
  noStroke();
  rect(16, 16, 420, 136, 10);
  fill(255);
  textSize(12);
  text(
    "Truchet Aesthetic Playground\n" +
    "[1..6]=Style  R=Reseed  P=Palette  G=Grid  M=Mirror\n" +
    "[ / ]=Tile  , / .=Stroke  S=Save PNG  H=Help\n" +
    "tile="+tile+"  sw="+nf(sw,1,1)+"  style="+style+"  palette="+paletteId+
    "  seed="+seedBase, 28, 40);
  popStyle();
}

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?