xxxxxxxxxx
259
// shoutout mohamad aljanabi https://youtu.be/Cv7Sbuuo2X8
// ok so now the hard part: turning the lines into uninterrupted polygons
// and then from that it makes polygon arrays for the actual tiles, could be similar to the voronoi construction method, along with an array of coordinates/rotation
// then the function that draws all of them
// basically my ratios. maybe i can tweak em
const gp1 = 0.25;
const gp2 = 0.5;
let gp3 = 0.1; //i think maybe actually this is the only one i can tweak without breaking 45 degree relations (and like; everything)
let startingPoint = [0, 1];
let conPts = [];
let lPts = [];
let lPts2 = [];
let prevDir;
let errorBreaker = 0;
let slider;
function setup() {
createCanvas(400, 400);
strokeWeight(3);
noFill();
strokeCap(SQUARE);
slider = createSlider(1, 20, 6);
slider.style("width", width + "px");
createButton("regenerate")
.mousePressed(regen)
.position(10, height + 30);
createButton("save png")
.mousePressed(savePNG)
.position(90, height + 30);
createButton("save pattern data")
.mousePressed(saveCSV)
.position(160, height + 30);
constructionPoints();
// ok now it has to actually make the lines between them lmao
// traditional tiling: mirror hor and vert to make a tile,
// rules:
// 1. diagonal symmetry: R should match B and T should match L.
// 2. prevent infinite tiles: this happens when there is an uninterrupted connection between T&B or L&R.
// 3. no 180 degree turns!
// 4. (optional) no full horizontal or vertical lines
// method 1: draw a line from bottom left corner through some points, bounce when it hits a normal wall and end when it hits the left wall, it should touch or cross the diagonal at least once (r2) -> do not go left until the diagonal is hit
// then mirror over diagonal(r1), derive tiles from intersections.
generatePath();
}
function draw() {
background(220);
angleMode(DEGREES);
// // draw construction points
// for(let i=0;i<conPts.length;i++){
// point(conPts[i][0]*width, conPts[i][1] * height);
// fill(0)
// text(i, conPts[i][0]*width, conPts[i][1] * height)
// noFill()
// }
let tile = slider.value();
let size = width / tile;
for (let j = 0; j < tile; j++) {
for (let k = 0; k < tile; k++) {
translate(k * 2 * size, j * 2 * size);
for (let i = 0; i < 4; i++) {
drawShape(size);
rotate(90);
translate(0, -2 * size);
}
translate(-k * 2 * size, -j * 2 * size);
}
}
}
function drawShape(size) {
beginShape();
for (let i = 0; i < lPts.length; i++) {
vertex(lPts[i][0] * size, lPts[i][1] * size);
}
endShape();
beginShape();
for (let i = 0; i < lPts2.length; i++) {
vertex(lPts2[i][0] * size, lPts2[i][1] * size);
}
endShape();
}
function regen() {
// gp3 = map(mouseX,0,width,0,0.25);
constructionPoints();
generatePath();
print(lPts.length)
}
function constructionPoints() {
// generate construction points
conPts = [];
for (let i = gp1; i < gp1 * 16; i += 2 * gp1) {
let startx = floor(i) * gp1;
let starty = (i % (gp1 * 8)) % (gp1 * 5);
conPts.push(
[startx + gp3, starty],
[startx - gp3, starty],
[startx, starty + gp3],
[startx, starty - gp3]
);
}
// move points around a bit
for (let i = 0; i < conPts.length * 2; i++) {
if (conPts[floor(i / 2)][i % 2] < 0) {
conPts[floor(i / 2)][i % 2] = conPts[floor(i / 2)][i % 2] + 1;
} else if (conPts[floor(i / 2)][i % 2] == 0) {
conPts.push([0.01, 0.01]);
conPts[conPts.length - 1][i % 2] = conPts[floor(i / 2)][i % 2] + 1;
conPts[conPts.length - 1][1 - (i % 2)] =
conPts[floor(i / 2)][1 - (i % 2)];
}
}
conPts.push([0, 0], [0, 1], [1, 0], [1, 1]); //add the corners
}
function generatePath() {
let hitDia = false;
lPts = [startingPoint];
for (let i = 0; i < 100; i++) {
// down, right, up, left, sw, nw, ne, se
let dirs = [[], [], [], [], [], [], [], []];
// check availabile jumps
for (let j = 0; j < conPts.length; j++) {
// check orth directions
for (let k = 0; k < 2; k++) {
if (conPts[j][k] == lPts[i][k] && conPts[j][1 - k] != lPts[i][1 - k]) {
//x, y
dirs[k + 1 + Math.sign(lPts[i][1 - k] - conPts[j][1 - k])].push(j);
}
}
// check diagonal directions
for (let k = -1; k < 2; k += 2) {
if (
round(100 * (lPts[i][0] - conPts[j][0])) ==
round(100 * (k * (lPts[i][1] - conPts[j][1]))) &&
conPts[j][0] != lPts[i][0]
) {
//this whole *100 and rounding is fucked but id need to make everything 100 to fix it i think
dirs[5 + (1 + k) / 2 + Math.sign(conPts[j][0] - lPts[i][0])].push(j);
}
}
}
// choose direction
let dir = findDir(dirs, hitDia);
let newpoint = conPts[dirs[dir][floor(random(0, dirs[dir].length))]];
errorBreaker = 0;
while(abs(lPts[i][0] - newpoint[0]) == 1 ||
abs(lPts[i][1] - newpoint[1]) == 1){
if(dirs[dir].length == 1){
dir = findDir(dirs, hitDia);
}
newpoint = conPts[dirs[dir][floor(random(0, dirs[dir].length))]];
errorBreaker++;
if (errorBreaker > 50) {
print("error 2!");
print(lPts[i], dirs);
break;
}
}
prevDir = dir;
lPts.push([newpoint[0], newpoint[1]]);
if (lPts[i + 1][0] > lPts[i + 1][1]) {
hitDia = true;
}
if (hitDia && lPts[i + 1][0] == 0) {
break;
}
}
lPts2 = [];
for (let i = 0; i < lPts.length; i++) {
lPts2.push([lPts[i][1], lPts[i][0]]);
}
}
function findDir(dirs, hitDia){
let dir = floor(random(0, 8));
errorBreaker = 0;
while (
(dir >= 3 && dir <= 5 && hitDia == false) ||
dirs[dir].length == 0 ||
dir % 4 == (prevDir + 2) % 4 ||
dir == prevDir
) {
dir = floor(random(0, 8));
errorBreaker++;
if (errorBreaker > 50) {
print("error 1!");
break;
}
}
return dir;
}
function savePNG(){
saveCanvas()
}
function saveCSV(){
let data = new p5.Table();
data.addColumn('x');
data.addColumn('y');
for(let i=0;i<lPts.length;i++){
let newRow = data.addRow();
newRow.setNum('x', lPts[i][0]);
newRow.setNum('y', lPts[i][1]);
}
for(let i=0;i<lPts2.length;i++){
let newRow = data.addRow();
newRow.setNum('x', lPts2[i][0]);
newRow.setNum('y', lPts2[i][1]);
}
saveTable(data, 'pattern.csv');
}