😽

[p5js]棒針編みの編み図を自動作成する

に公開

この記事は何?

編み物大好きマンが狂った結果p5jsを使って編み図を自動生成する方法を思いついたのでメモしたもの。

グリッドを用意

まず簡単なグリッドを用意する。

let cellSize = 30; // 各編み目のサイズ
let gridCols, gridRows;
let offsetX, offsetY;

function setup() {
  createCanvas(800, 800);
  calcGrid();
}

function calcGrid() {
  // キャンバスに収まるグリッド数
  gridCols = floor(width / cellSize);
  gridRows = floor(height / cellSize);

  // 中央配置オフセット
  offsetX = (width - gridCols * cellSize) / 2;
  offsetY = (height - gridRows * cellSize) / 2;
}

function draw() {
  background(255);

  drawGrid();
}

function drawGrid() {
  stroke(200);
  strokeWeight(1);

  // 縦線
  for (let i = 0; i <= gridCols; i++) {
    let x = offsetX + i * cellSize;
    line(x, offsetY, x, offsetY + gridRows * cellSize);
  }

  // 横線
  for (let j = 0; j <= gridRows; j++) {
    let y = offsetY + j * cellSize;
    line(offsetX, y, offsetX + gridCols * cellSize, y);
  }
}


// キーボード入力でキャンバスを保存
function keyPressed() {
  if (key === "s") {
    saveCanvas("knitting-chart", "png");
  }
}


やっていることは、

function calcGrid() {
  gridCols = floor(width / cellSize);
  gridRows = floor(height / cellSize);

  offsetX = (width - gridCols * cellSize) / 2;
  offsetY = (height - gridRows * cellSize) / 2;
}

1.キャンバスに何マス入るか計算する
2.グリッド全体を中央に配置するための余白を計算

例えば
・800px のキャンバス
・グリッド幅 = 26 マス × 30 = 780px
・余り = 20px
・片側 10px 開ければ中央になる → 10px を offset に

function drawGrid() {
  stroke(200);
  strokeWeight(1);

  // 縦線
  for (let i = 0; i <= gridCols; i++) {
    let x = offsetX + i * cellSize;
    line(x, offsetY, x, offsetY + gridRows * cellSize);
  }

  // 横線
  for (let j = 0; j <= gridRows; j++) {
    let y = offsetY + j * cellSize;
    line(offsetX, y, offsetX + gridCols * cellSize, y);
  }
}

offsetとcellSizeを使って縦と横の線を描く。

0と1を使って編み図を描いていく

次に0と1を使って編み図を描く。
https://editor.p5js.org/Karakure178/sketches/tNBdEOH86

実際のコード
// ===== 基本設定 =====
let cellSize = 30; // 1目のサイズ(px)
let gridCols, gridRows;
let offsetX, offsetY;

// 7x7 の棒針編みパターン(0: 表目, 1: 裏目)
const patternSize = 7;
const currentPattern = [
  [0, 0, 0, 0, 0, 0, 0],
  [0, 1, 1, 0, 1, 1, 0],
  [0, 1, 0, 0, 0, 1, 0],
  [0, 0, 0, 1, 0, 0, 0],
  [0, 1, 0, 0, 0, 1, 0],
  [0, 1, 1, 0, 1, 1, 0],
  [0, 0, 0, 0, 0, 0, 0],
];

function setup() {
  createCanvas(800, 800);
  calcGrid();
}

function calcGrid() {
  // キャンバスに収まるグリッド数
  gridCols = floor(width / cellSize);
  gridRows = floor(height / cellSize);

  // 中央配置オフセット
  offsetX = (width - gridCols * cellSize) / 2;
  offsetY = (height - gridRows * cellSize) / 2;
}

function draw() {
  background(255);

  // 先に編み記号(マス)を描く
  drawPattern();

  // 上からグリッド線をかぶせる
  drawGrid();
}

// ===== 編み図パターンを描く部分 =====
function drawPattern() {
  for (let i = 0; i < gridCols; i++) {
    for (let j = 0; j < gridRows; j++) {
      let x = offsetX + i * cellSize;
      let y = offsetY + j * cellSize;

      // 7x7 パターンを繰り返し適用
      let patternX = i % patternSize;
      let patternY = j % patternSize;
      let symbol = currentPattern[patternY][patternX];

      drawSymbol(symbol, x, y, cellSize);
    }
  }
}

// 記号(1マス)を描く
function drawSymbol(symbol, x, y, size) {
  push();
  noStroke();

  if (symbol === 0) {
    // 表目:白
    fill(255);
  } else if (symbol === 1) {
    // 裏目:赤
    fill(255, 0, 0);
  }

  rect(x, y, size, size);
  pop();
}

// ===== グリッド線を描く部分 =====
function drawGrid() {
  stroke(200);
  strokeWeight(1);

  // 縦線
  for (let i = 0; i <= gridCols; i++) {
    let x = offsetX + i * cellSize;
    line(x, offsetY, x, offsetY + gridRows * cellSize);
  }

  // 横線
  for (let j = 0; j <= gridRows; j++) {
    let y = offsetY + j * cellSize;
    line(offsetX, y, offsetX + gridCols * cellSize, y);
  }
}

// キーボード入力でキャンバスを保存
function keyPressed() {
  if (key === "s") {
    saveCanvas("knitting-chart", "png");
  }
}

以下解説。

// 7x7 の棒針編みパターン(0: 表目, 1: 裏目)
const patternSize = 7;
const currentPattern = [
  [0, 0, 0, 0, 0, 0, 0],
  [0, 1, 1, 0, 1, 1, 0],
  [0, 1, 0, 0, 0, 1, 0],
  [0, 0, 0, 1, 0, 0, 0],
  [0, 1, 0, 0, 0, 1, 0],
  [0, 1, 1, 0, 1, 1, 0],
  [0, 0, 0, 0, 0, 0, 0],
];

実際に表示したいパターンを記載する。
表目を0、裏目を1で記載している。

// ===== 編み図パターンを描く部分 =====
function drawPattern() {
  for (let i = 0; i < gridCols; i++) {
    for (let j = 0; j < gridRows; j++) {
      let x = offsetX + i * cellSize;
      let y = offsetY + j * cellSize;

      // 7x7 パターンを繰り返し適用
      let patternX = i % patternSize;
      let patternY = j % patternSize;
      let symbol = currentPattern[patternY][patternX];

      drawSymbol(symbol, x, y, cellSize);
    }
  }
}

キャンバスマス全体をfor文で回して編み図をタイル状に配置。
この時、i,j をパターンサイズ(7)で割った余りを使う。
つまり パターンが無限に繰り返される
・i=7 の時 → 7 % 7 = 0
・i=8 の時 → 8 % 7 = 1

// 記号(1マス)を描く
function drawSymbol(symbol, x, y, size) {
  push();
  noStroke();

  if (symbol === 0) {
    // 表目:白
    fill(255);
  } else if (symbol === 1) {
    // 裏目:赤
    fill(255, 0, 0);
  }

  rect(x, y, size, size);
  pop();
}

編み図記号を描く。

if (symbol === 0) fill(255);         // 表目
else if (symbol === 1) fill(255, 0, 0); // 裏目

ここで色付けを行っている。

このようにcurrentPatternを変更すれば無限に模様を楽しむことができる。
模様はAIに聞けばいくらでも出してくれる。
なんてすてきな世界なのでしょう!!

Discussion