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?

Semi regular tilings

Posted at

image.png

重複あり版

structure4346.pde
// ==================================================
// メインスケッチ
// ==================================================

ArrayList<PolyBase> polys; // すべての多角形をここに入れる

void setup() {
  size(800, 800);

  polys = new ArrayList<PolyBase>();

  // 1. 中心の正六角形を1つ置く
  polys.add(new PolyBase(400, 400, 50, radians(30), 6));

  // 2. 六角形の6つの辺から正方形(4角形)を生やす
  //    生成した正方形はpolys に追加する
  int m = polys.size();             // 追加前の要素数を固定
  for (int k = 0; k < m; k++) {     // ここでは元からある要素だけを見る
    PolyBase p = polys.get(k);
    if (p.n != 6) continue;
    for (int ei = 0; ei < p.n; ei++) {  // 六角形の6辺すべてに四角形を追加
      polys.add(p.makePolygonOnEdge(ei, 4));
    }
  }

  m = polys.size();
  for (int k = 0; k < m; k++) {
    PolyBase p = polys.get(k);
    if (p.n != 4) continue;
    polys.add(p.makePolygonOnEdge(0, 3));// 四角形の辺から三角形を生やす
  }

  m = polys.size();
  for (int k = 0; k < m; k++) {
    PolyBase p = polys.get(k);
    if (p.n != 4) continue;
    polys.add(p.makePolygonOnEdge(1, 6));// 四角形の辺から六角形を生やす
  }

  m = polys.size();
  for (int k = 0; k < m; k++) {
    PolyBase p = polys.get(k);
    if (p.n != 6) continue;
    for (int ei = 0; ei < p.n; ei++) {  // 六角形の6辺すべてに四角形を追加
      polys.add(p.makePolygonOnEdge(ei, 4));
    }
  }

  m = polys.size();
  for (int k = 0; k < m; k++) {
    PolyBase p = polys.get(k);
    if (p.n != 4) continue;
    polys.add(p.makePolygonOnEdge(0, 3));// 四角形の辺から三角形を生やす
  }
}

void draw() {
  background(255);

  // すべての多角形を描画
  strokeWeight(1);
  for (PolyBase p : polys) {
    p.draw();
  }

  // 法線のデバッグ線も描画
  for (PolyBase p : polys) {
    p.drawNormals();
  }
}



// ==================================================
// PolyBase クラス
// ==================================================
//
// 正n角形を表す基本クラス。
// n=3 なら正三角形、4なら正方形、6なら正六角形、など。
// このクラスだけで、すべての多角形を扱う。
// さらに、自分の任意の辺の外側に別の正n角形を「生やす」こともできる。
//
class PolyBase {
  PVector center;   // 中心
  float   R;        // 中心→各頂点までの距離(外接半径)
  float   rotation; // 頂点0の向き(ラジアン)
  int     n;        // 角数(3,4,6,...)

  PVector[] v;      // 頂点座標(CCW)
  float[]   th;     // 各頂点の角度(中心から見た角度)
  PVector[] mid;    // 各辺の中点
  PVector[] normal; // 各辺の外向き法線(単位ベクトル)

  // --------------------------------
  // コンストラクタ
  // --------------------------------
  PolyBase(float cx, float cy, float R_, float rot, int n_) {
    center   = new PVector(cx, cy);
    R        = R_;
    rotation = rot;
    n        = n_;

    v      = new PVector[n];
    th     = new float[n];
    mid    = new PVector[n];
    normal = new PVector[n];

    compute();
  }

  // --------------------------------
  // 頂点/中点/法線を計算
  // --------------------------------
  void compute() {
    // 頂点と角度(CCWに並べる)
    for (int i=0; i<n; i++) {
      float a = rotation + TWO_PI * i / n;
      th[i] = a;
      v[i] = new PVector(center.x + R * cos(a),
        center.y + R * sin(a));
    }

    // 各辺の中点と外向き法線
    for (int i=0; i<n; i++) {
      PVector A = v[i];
      PVector B = v[(i+1)%n];

      // 中点
      mid[i] = new PVector(
        (A.x + B.x) * 0.5,
        (A.y + B.y) * 0.5
        );

      // 辺ベクトル e = B - A
      PVector e = PVector.sub(B, A);

      // いったん「左法線」をとる
      PVector nL = new PVector(-e.y, e.x);

      // 中心→中点ベクトルと内積をとって、
      // ちゃんと外向きになるように向きをそろえる
      PVector cm = PVector.sub(mid[i], center);
      if (PVector.dot(nL, cm) < 0) {
        nL.mult(-1);
      }
      nL.normalize();
      normal[i] = nL;
    }
  }

  // --------------------------------
  // 描画(輪郭)
  // --------------------------------
  void draw() {
    stroke(0);
    noFill();
    beginShape();
    for (int i=0; i<n; i++) {
      vertex(v[i].x, v[i].y);
    }
    endShape(CLOSE);
  }

  // --------------------------------
  // 法線ベクトルの可視化(デバッグ用)
  // --------------------------------
  void drawNormals() {
    stroke(200, 0, 200); // マゼンタ
    noFill();
    for (int i=0; i<n; i++) {
      PVector m  = mid[i];
      PVector nn = normal[i];
      line(m.x, m.y,
        m.x + nn.x * 10,
        m.y + nn.y * 10);
    }
  }

  // --------------------------------
  // 新しい正sides角形を、自分のei番目の辺の外側に生やす
  //
  // 返り値は新しく生成した PolyBase
  // --------------------------------
  PolyBase makePolygonOnEdge(int ei, int sides) {
    // ei を 0..n-1 に正規化
    int i = ((ei % n) + n) % n;

    // この辺の両端 A, B
    PVector A = v[i];
    PVector B = v[(i+1)%n];

    // 辺ベクトル e と その長さ s
    PVector e = PVector.sub(B, A);
    float s   = e.mag();  // この長さを新しい多角形の1辺にする

    // 辺の中点 m と 外向き法線 nOut
    PVector m    = mid[i];
    PVector nOut = normal[i]; // 単位ベクトルで外向き

    // 正sides角形の幾何パラメータ
    // 外接半径(中心→頂点)
    //   Rchild = s / (2 * sin(pi / sides))
    float Rchild = s / (2.0 * sin(PI / sides));

    // アポセム(辺の中点→中心の距離)
    //   apothem = s / (2 * tan(pi / sides))
    float apothem = s / (2.0 * tan(PI / sides));

    // 子ポリゴンの中心Cは、
    // 親の辺の中点 m から、外向き法線方向に apothem だけ進んだ場所
    PVector C = new PVector(
      m.x + nOut.x * apothem,
      m.y + nOut.y * apothem
      );

    // 子ポリゴンの回転は、
    // 「中心Cから親の頂点Aへ向かうベクトルの角度」を使う。
    // これで子ポリゴンの v[0] が A に一致する向きになる。
    float rotationChild = atan2(A.y - C.y, A.x - C.x);

    // 新しい正sides角形として返す
    PolyBase child = new PolyBase(
      C.x, C.y,
      Rchild,
      rotationChild,
      sides
      );

    return child;
  }
}

HashSetで重複を削除

structure4346.pde
// ==================================================
// メインスケッチ
// ==================================================

ArrayList<PolyBase> polys; // すべての多角形
import java.util.HashSet;

HashSet<String> seen;      // すでに追加済みのポリゴンのキー

void setup() {
  size(800, 800);

  polys = new ArrayList<PolyBase>();
  seen  = new HashSet<String>();

  // 1. 中心の正六角形を1つ置く(まずはaddUniqueで追加)
  addUnique(new PolyBase(400, 400, 50, radians(30), 6));

  // 2. 六角形 → 全辺に正方形(4角形)
  int m = polys.size();
  for (int k = 0; k < m; k++) {
    PolyBase p = polys.get(k);
    if (p.n != 6) continue;
    for (int ei = 0; ei < p.n; ei++) {
      addUnique(p.makePolygonOnEdge(ei, 4));
    }
  }

  // 3. 四角形 → 辺0に三角形(3角形)
  m = polys.size();
  for (int k = 0; k < m; k++) {
    PolyBase p = polys.get(k);
    if (p.n != 4) continue;
    addUnique(p.makePolygonOnEdge(0, 3));
  }

  // 4. 四角形 → 辺1に六角形(6角形)
  m = polys.size();
  for (int k = 0; k < m; k++) {
    PolyBase p = polys.get(k);
    if (p.n != 4) continue;
    addUnique(p.makePolygonOnEdge(1, 6));
  }

  // 5. さらに、六角形 → 全辺に正方形(4角形) もう一度拡張
  m = polys.size();
  for (int k = 0; k < m; k++) {
    PolyBase p = polys.get(k);
    if (p.n != 6) continue;
    for (int ei = 0; ei < p.n; ei++) {
      addUnique(p.makePolygonOnEdge(ei, 4));
    }
  }

  // 6. 四角形 → 辺0に三角形(3角形) もう一段
  m = polys.size();
  for (int k = 0; k < m; k++) {
    PolyBase p = polys.get(k);
    if (p.n != 4) continue;
    addUnique(p.makePolygonOnEdge(0, 3));
  }

  // 7. 四角形 → 辺1に六角形(6角形)
  m = polys.size();
  for (int k = 0; k < m; k++) {
    PolyBase p = polys.get(k);
    if (p.n != 4) continue;
    addUnique(p.makePolygonOnEdge(1, 6));
  }

  // 8. さらに、六角形 → 全辺に正方形(4角形) もう一度拡張
  m = polys.size();
  for (int k = 0; k < m; k++) {
    PolyBase p = polys.get(k);
    if (p.n != 6) continue;
    for (int ei = 0; ei < p.n; ei++) {
      addUnique(p.makePolygonOnEdge(ei, 4));
    }
  }

  // 9. 四角形 → 辺0に三角形(3角形) もう一段
  m = polys.size();
  for (int k = 0; k < m; k++) {
    PolyBase p = polys.get(k);
    if (p.n != 4) continue;
    addUnique(p.makePolygonOnEdge(0, 3));
  }

  //六角形の総数
  int HexNum=0, TriNum=0, SqNum=0;
  for (PolyBase p : polys) {
    if (p.n == 3) TriNum++;
    if (p.n == 4) SqNum++;
    if (p.n == 6) HexNum++;
  }
  println("Tri:", TriNum);
  println("Sq:", SqNum);
  println("Hex:", HexNum);
}

void draw() {
  background(255);

  strokeWeight(1);
  for (PolyBase p : polys) {
    p.draw();
  }

  // 法線だけを表示(中点の点や中心の点は描かない)
  for (PolyBase p : polys) {
    p.drawNormals();
  }
}


// ==================================================
// ユーティリティ: 重複なしでpolysに追加
// ==================================================

// PolyBaseを固有キー文字列にする
String makeKey(PolyBase p) {
  // 小数点以下を1000倍・丸めして安定化
  int cx = round(p.center.x * 1000);
  int cy = round(p.center.y * 1000);
  return cx + ":" + cy;
}

// まだ存在しない形ならpolysとseenに登録する
void addUnique(PolyBase p) {
  String key = makeKey(p);
  if (!seen.contains(key)) {
    seen.add(key);
    polys.add(p);
  }
}


// ==================================================
// PolyBase クラス
// ==================================================

class PolyBase {
  PVector center;   // 中心
  float   R;        // 中心→各頂点までの距離(外接半径)
  float   rotation; // 頂点0の向き(ラジアン)
  int     n;        // 角数(3,4,6,...)

  PVector[] v;      // 頂点座標(CCW)
  float[]   th;     // 各頂点の角度
  PVector[] mid;    // 各辺の中点
  PVector[] normal; // 各辺の外向き法線(単位ベクトル)

  PolyBase(float cx, float cy, float R_, float rot, int n_) {
    center   = new PVector(cx, cy);
    R        = R_;
    rotation = rot;
    n        = n_;

    v      = new PVector[n];
    th     = new float[n];
    mid    = new PVector[n];
    normal = new PVector[n];

    compute();
  }

  void compute() {
    // 頂点と角度
    for (int i=0; i<n; i++) {
      float a = rotation + TWO_PI * i / n;
      th[i] = a;
      v[i] = new PVector(center.x + R * cos(a),
        center.y + R * sin(a));
    }

    // 各辺の中点と外向き法線
    for (int i=0; i<n; i++) {
      PVector A = v[i];
      PVector B = v[(i+1)%n];

      mid[i] = new PVector(
        (A.x + B.x) * 0.5,
        (A.y + B.y) * 0.5
        );

      // 辺ベクトル
      PVector e = PVector.sub(B, A);

      // 左法線
      PVector nL = new PVector(-e.y, e.x);

      // 外向きにそろえる
      PVector cm = PVector.sub(mid[i], center);
      if (PVector.dot(nL, cm) < 0) {
        nL.mult(-1);
      }
      nL.normalize();
      normal[i] = nL;
    }
  }

  void draw() {
    stroke(0);
    noFill();
    beginShape();
    for (int i=0; i<n; i++) {
      vertex(v[i].x, v[i].y);
    }
    endShape(CLOSE);
  }

  void drawNormals() {
    stroke(200, 0, 200); // マゼンタ
    noFill();
    for (int i=0; i<n; i++) {
      PVector m  = mid[i];
      PVector nn = normal[i];
      line(m.x, m.y,
        m.x + nn.x * 10,
        m.y + nn.y * 10);
    }
  }

  PolyBase makePolygonOnEdge(int ei, int sides) {
    int i = ((ei % n) + n) % n;

    // 親の辺 A->B
    PVector A = v[i];
    PVector B = v[(i+1)%n];

    // 一辺の長さ
    PVector e = PVector.sub(B, A);
    float s   = e.mag();

    // 辺の中点と外向き法線
    PVector m    = mid[i];
    PVector nOut = normal[i];

    // 子ポリゴンのジオメトリ
    float Rchild  = s / (2.0 * sin(PI / sides));
    float apothem = s / (2.0 * tan(PI / sides));

    // 子ポリゴン中心
    PVector C = new PVector(
      m.x + nOut.x * apothem,
      m.y + nOut.y * apothem
      );

    // 回転
    float rotationChild = atan2(A.y - C.y, A.x - C.x);

    // 生成
    return new PolyBase(
      C.x, C.y,
      Rchild,
      rotationChild,
      sides
      );
  }
}

aaa

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?