ここでは、正三角形と正十二角形によるタイリングを再現してみました。なお、今回のタイリングを作成するにあたって、書籍「アートで魅せる数学の世界」の「2種類以上の正多角形によるタイリング」(p.94)を参考にしました。

正三角形と正十二角形

タイリング〈正三角形と正十二角形〉は以下のような図形になります。

正三角形と正十二角形

以下で、このタイリング〈正三角形と正十二角形〉の描き方について解説していきます。

正三角形と正十二角形の描き方

対称性について

まず、このタイリング〈正三角形と正十二角形〉の対称性について考えます。

正三角形と正十二角形の対称性

上図のように、タイリングのパターンをじっくり見ていくと、上図の赤丸の周りの180°回転、青丸の周りの120°回転、および緑丸の周りの60°回転に対して図形は回転対称になっていることが分かります。そして縦横、斜め方向の赤色の線に対して図形は鏡映対称であり、赤色の点線の軸に対して図形はすべり鏡映対称であることがわかります。また、黒色の点を格子としてみると、近接する3つの黒色の点同士が正三角形を形作っていることから、黒色の点は三角格子になっていることが分かります。これらをまとめると、タイリング〈正三角形と正十二角形〉は、壁紙群P6Mの対称性を持つことが分かります。

アイソヘドラルタイリングの観点でみると、IH20(P6M)IH77(P6M)IH92(P6M)のいずれにも分類することができますが、今回は基本図形が一番細かくなるIH77(P6M)で再現しました。

基本図形の準備

タイリング〈正三角形と正十二角形〉に現れる正三角形や正十二角形の一辺の長さを\(1\)とすると、タイリング〈正三角形と正十二角形〉の基本図形は、斜辺の長さが\(1/\sqrt{3}\)となる30°、60°、90°の直角三角形と、辺の長さがそれぞれ\(1/2, \ 1/2, \ (\sqrt{3}+2)/2, \ (\sqrt{3}+2)/2\)となる凧型の四角形を組み合わせたものになります(下図参照)。

正三角形と正十二角形の基本図形

三角格子の準備

また、三角格子は、上図の基本図形で示したように、辺の長さがそれぞれ\(1/2, \ 1/2, \ (\sqrt{3}+2)/2, \ (\sqrt{3}+2)/2\)となる凧型の四角形の2つの頂点が近接する三角格子点となるように準備します。

壁紙群P6Mの対称性に合わせて並べる

ここまで準備ができたら、あとは壁紙群P6Mの対称性に合わせて基本図形を並べていくことでタイリング〈正三角形と正十二角形〉を作成することができます。

ソースコード

今回再現したタイリング〈正三角形と正十二角形〉のプログラムのソースコードを示しておきます。

PVector[][] lattice; // 格子点ベクトル
PShape tile; // タイル
PVector[] base = new PVector[2]; // 格子を張るベクトル
int col_num = 16; // 描画するタイルの列の数
float scalar; // タイルの辺の長さ

void setup(){

  size(1000, 1000, P2D);
  noFill();
  noLoop();
  scalar = width * 1.0 / col_num; // 描画ウィンドウと行の数からタイルの大きさを決定
  makeTriangleVector(); // 三角格子を張るベクトルの生成
  makeLattice(); // 格子点ベクトルを生成
  makeTileP6M(); // タイルを生成
  drawTiling(); // タイリングを描画
}

// 三角格子を張るベクトルを生成する関数
void makeTriangleVector(){
  base[0] = new PVector(1.0, 0.0);
  base[1] = PVector.fromAngle(PI / 3);
}

// 三角格子を生成する関数
void makeLattice(){
  int row_num = ceil(col_num / base[1].x); // 行の数
  lattice = new PVector[col_num + 5][row_num + 1];
  for (int i = 0; i < col_num + 5; i++){
    for (int j = 0; j < row_num + 1; j++){
      PVector v = PVector.mult(base[0], (i-4) * scalar * (sqrt(3.0)+2.0) / 2.0 ); 
      v.add(PVector.mult(base[1], j * scalar * (sqrt(3.0)+2.0) / 2.0 ));
      lattice[i][j] = new PVector(v.x, v.y); 
    }
  }
}

// 直角三角形を生成する関数(基本図形)
PShape makeRightTriangle(){

  PVector[] v = new PVector[3]; // 直角三角形の頂点
  
  v[0] = new PVector(0.0,0.0);
  v[1] = PVector.fromAngle(PI / 6.0);
  v[1].mult( scalar * (sqrt(3.0)+2.0) / sqrt(3.0) );  
  v[2] = new PVector(1.0,0.0);
  v[2].mult( scalar * (sqrt(3.0)+2.0) / 2.0 );

  PVector[] v_middle = new PVector[2];
  v_middle[0] = v[1].copy().mult(sqrt(3.0)/2.0);
  v_middle[1] = v[1].copy().add( v[2].copy().sub(v[1].copy()).mult(2.0*(2.0-sqrt(3.0))) );
  
  PShape rightTri = createShape(GROUP);
  
  // 内部の凧型の図形を描く
  fill(0,0,255);
  noStroke();
  PShape kite = createShape();  
  kite.beginShape(); 
  kite.vertex(v[0].x, v[0].y);
  kite.vertex(v_middle[0].x, v_middle[0].y);
  kite.vertex(v_middle[1].x, v_middle[1].y);
  kite.vertex(v[2].x, v[2].y);
  kite.endShape();
  rightTri.addChild(kite);

  // 内部の直角三角形を描く 
  fill(255,255,0);
  PShape rightTri1 = createShape();  
  rightTri1.beginShape(TRIANGLES); 
  rightTri1.vertex(v_middle[0].x, v_middle[0].y);
  rightTri1.vertex(v[1].x, v[1].y);
  rightTri1.vertex(v_middle[1].x, v_middle[1].y);
  rightTri1.endShape();
  rightTri.addChild(rightTri1);

  // 凧型の一部の輪郭を描く
  stroke(0,0,0);
  PShape kite_line = createShape();
  kite_line.beginShape(); 
  kite_line.vertex(v_middle[1].x, v_middle[1].y);
  kite_line.vertex(v[2].x, v[2].y);
  kite_line.vertex(v_middle[1].x, v_middle[1].y);
  kite_line.endShape(CLOSE);
  rightTri.addChild(kite_line);
 
  return rightTri;
}

// タイルを生成する関数
void makeTileP6M(){
  tile = createShape(GROUP); // PShapeのグループを作る
  for (int i=0; i<6; i++){
    PShape positiveTri = createShape(GROUP); // 直角三角形を2つ合わせて正三角形を生成
    for (int j=0; j<2; j++){
      PShape rightTri = makeRightTriangle(); // 直角三角形の生成
      rightTri.scale(1, pow(-1, j)); // x軸を中心に鏡映
      positiveTri.addChild(rightTri);
    }
    positiveTri.rotate(PI * i / 3.0); // 60度回転
    tile.addChild(positiveTri); // グループに追加
  }
}

// 格子形状に合わせたタイリングを描画する関数
void drawTiling(){
//  background(255);
  for (int i=0; i<lattice.length; i++){
    for (int j=0; j<lattice[0].length; j++){
      if( i%2 == 0 && j%2 == 0 ){
        tile.resetMatrix();
        tile.translate(lattice[i][j].x, lattice[i][j].y); // タイルの位置を指定
        shape(tile); // タイルを描画
      }
    }
  }
}

参考

参考までに、アイソヘドラルタイリングIH20(P6M)IH92(P6M)とみなしたときの基本図形を示しておきます。

IH20(P6M)とした場合の基本図形
IH92(P6M)とした場合の基本図形