重複あり版
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
