diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..b1e6aa6 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "liveServer.settings.port": 5501 +} \ No newline at end of file diff --git a/liberay.html b/liberay.html index 2f4dac1..de56202 100644 --- a/liberay.html +++ b/liberay.html @@ -30,7 +30,13 @@ const sketches = sketchList.split(','); for (let sketch of sketches) { const iframe = document.createElement('iframe'); - iframe.src = `loader.html?sketch=${encodeURIComponent(sketch)}`; + iframe.src = `loader.html?sketches=${encodeURIComponent(sketch.trim())}`; + iframe.onload = () => { + console.log(`Loaded iframe for ${sketch}`); + }; + iframe.onerror = () => { + console.error(`Failed to load iframe for ${sketch}`); + }; // Apply size if provided if (sketchSize) { iframe.style.width = sketchSize + 'px'; @@ -41,6 +47,8 @@ } document.body.appendChild(iframe); } + } else { + console.error('No sketches parameter provided'); } diff --git a/loader.html b/loader.html index cc6fada..8c5063a 100644 --- a/loader.html +++ b/loader.html @@ -4,21 +4,37 @@ - + @@ -27,5 +43,16 @@ margin: 0; overflow: hidden; } + #error { + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background: white; + border: 2px solid red; + border-radius: 8px; + padding: 20px; + max-width: 400px; + } \ No newline at end of file diff --git a/sketches/L-System.js b/sketches/L-System.js index 453bcc7..3cea30a 100644 --- a/sketches/L-System.js +++ b/sketches/L-System.js @@ -1,178 +1,257 @@ -let angle = 3.141592653589*1.5; -let angleDecrement = 1; -let stepSize = 10; -let widthIncrement = 1; -let currentWidth = 1; -let currentPosition = [501 / 2, 500]; -let fractalst = "FF+[+F-F-F]-[-F+F+F]"; -let stackList = []; -let lineLenghtScaleFactor = 1.5; +/* +L-System Fractal Generator + +The following characters have a geometric interpretation: + +Character Meaning + F Move forward by line length drawing a line + f Move forward by line length without drawing a line + + Turn left by turning angle + - Turn right by turning angle + | Reverse direction (ie: turn by 180 degrees) + [ Push current drawing state onto stack + ] Pop current drawing state from the stack + # Increment the line width by line width increment + ! Decrement the line width by line width increment + @ Draw a dot with line width radius + { Open a polygon + } Close a polygon and fill it with fill colour + > Multiply the line length by the line length scale factor + < Divide the line length by the line length scale factor + & Swap the meaning of + and - + ( Decrement turning angle by turning angle increment + ) Increment turning angle by turning angle increment +*/ + +let angle = Math.PI * 1.5; +let turningAngle = Math.PI * 0.5; +let lineLength = 5; +let lineWidthIncrement = 1; +let currentLineWidth = 1; +let currentPosition = [0, 0]; +let stateStack = []; +let lineLengthScaleFactor = 1.5; let swapPlusMinusState = false; let turningAngleIncrement = 0.1; +let polygonVertices = []; +let polygonOpen = false; -//FF+[+F-F-F]-[-F+F+F] fork +let axiom = 'F+F+F+F'; +let maxIterations = 4; +const maxCalculations = 50000; +let rules = { + 'F': 'FF+F-F+F+FF' +}; + +// Generate the fractal string from axiom and rules +for (let i = 0; i < maxIterations; i++) { + if (axiom.length > maxCalculations) {//hard coded limit to prevent infinite loops + console.log('Reached max calculations, stopping at iteration', i); + break; + } + let newAxiom = ''; + for (let char of axiom) {//loop through each character in the axiom and replace it with the corresponding rule + if (rules[char]) { + newAxiom += rules[char]; + } else { + newAxiom += char; + } + } + axiom = newAxiom; +} function setup() { - console.log("setup"); createCanvas(windowWidth, windowHeight); - background(255, 255, 255) + background(255, 255, 255); noFill(); stroke(0, 0, 0); - strokeWeight(1); - currentPosition = [width / 2, height]; + strokeWeight(currentLineWidth); + currentPosition = [width / 2, height - 100]; generateFractal(); } function generateFractal() { - for (let i = 0; i < fractalst.length; i++) { - let c = fractalst.charAt(i); + for (let i = 0; i < axiom.length; i++) { + let c = axiom.charAt(i); switch (c) { case "F": - forward(); - break; - case "+": - plus(); - break; - case "-": - minus(); + moveForwardDraw(); break; case "f": - forwardNoLine(); + moveForwardNoDraw(); + break; + case "+": + turnLeft(); + break; + case "-": + turnRight(); break; case "|": reverseDirection(); break; - case "#": - lineWidthIncrement(); - break; - case "!": - lineWidthDecrement(); - break; case "[": - pushStack(i); + pushState(i); break; case "]": - popStack(i); + popState(i); break; - case ">": - lineWidthMultiply(); + case "#": + incrementLineWidth(); break; - case "<": - lineWidthDivide(); - break; - case "&": - swapPlusMinus(); + case "!": + decrementLineWidth(); break; case "@": drawDot(); break; + case "{": + openPolygon(); + break; + case "}": + closePolygon(); + break; + case ">": + multiplyLineLength(); + break; + case "<": + divideLineLength(); + break; + case "&": + swapPlusMinus(); + break; case ")": - angleIncrement(); + incrementTurningAngle(); break; case "(": - angleDecrement(); + decrementTurningAngle(); break; default: - console.log("unrecognized character",c); + // Ignore characters not in the specification (like X) break; } } } -function minus() { - if (swapPlusMinusState) { - angle += angleDecrement; - return +// F: Move forward by line length drawing a line +function moveForwardDraw() { + let x = currentPosition[0] + cos(angle) * lineLength; + let y = currentPosition[1] + sin(angle) * lineLength; + if (polygonOpen) { + polygonVertices.push([x, y]); + } else { + line(currentPosition[0], currentPosition[1], x, y); } - angle -= angleDecrement; -} - -function plus() { - if (swapPlusMinusState) { - angle -= angleDecrement; - return - } - angle += angleDecrement; -} - -function lineWidthIncrement(){ - currentWidth + widthIncrement; - strokeWeight(currentWidth); -} - -function lineWidthDecrement(){ - currentWidth - widthIncrement; - strokeWeight(currentWidth); -} - -function forward() { - let x = currentPosition[0] + cos(angle) * stepSize; - let y = currentPosition[1] + sin(angle) * stepSize; - line(currentPosition[0], currentPosition[1], x, y); currentPosition = [x, y]; } -function forwardNoLine(){ - let x = currentPosition[0] + cos(angle) * stepSize; - let y = currentPosition[1] + sin(angle) * stepSize; +// f: Move forward by line length without drawing a line +function moveForwardNoDraw() { + let x = currentPosition[0] + cos(angle) * lineLength; + let y = currentPosition[1] + sin(angle) * lineLength; currentPosition = [x, y]; } -function backward() { - let x = currentPosition[0] - cos(angle) * stepSize; - let y = currentPosition[1] - sin(angle) * stepSize; - line(currentPosition[0], currentPosition[1], x, y); - currentPosition = [x, y]; -} - -function reverseDirection(){ - angle - 3.14159265358979323; -} - -function pushStack(i){ - console.log(angle) - stackList.push([i,currentPosition[0],currentPosition[1],angle,currentWidth]); -} - -function popStack(i){ - stackToPop = stackList.length - 1; - console.log(stackList[stackToPop]) - currentPosition = [stackList[stackToPop][1],stackList[stackToPop][2]]; - angle = stackList[stackToPop][3]; - strokeWeight[stackList[stackToPop][4]] -} - -function lineWidthMultiply(){ - currentWidth * lineLenghtScaleFactor; - strokeWeight(currentWidth); -} - -function lineWidthDivide(){ - currentWidth / lineLenghtScaleFactor; - strokeWeight(currentWidth); -} - -function swapPlusMinus(){ +// +: Turn left by turning angle +function turnLeft() { if (swapPlusMinusState) { - swapPlusMinusState = false; + angle -= turningAngle; return } - swapPlusMinusState = true; + angle += turningAngle; } +// -: Turn right by turning angle +function turnRight() { + if (swapPlusMinusState) { + angle += turningAngle; + return + } + angle -= turningAngle; +} + +// |: Reverse direction (turn by 180 degrees) +function reverseDirection() { + angle += Math.PI; +} + +// [: Push current drawing state onto stack +function pushState(i) { + stateStack.push([i, currentPosition[0], currentPosition[1], angle, currentLineWidth]); +} + +// ]: Pop current drawing state from the stack +function popState(i) { + let stackIndex = stateStack.length - 1; + currentPosition = [stateStack[stackIndex][1], stateStack[stackIndex][2]]; + angle = stateStack[stackIndex][3]; + currentLineWidth = stateStack[stackIndex][4]; + strokeWeight(currentLineWidth); +} + +// #: Increment the line width by line width increment +function incrementLineWidth() { + currentLineWidth += lineWidthIncrement; + strokeWeight(currentLineWidth); +} + +// !: Decrement the line width by line width increment +function decrementLineWidth() { + currentLineWidth -= lineWidthIncrement; + strokeWeight(currentLineWidth); +} + +// @: Draw a dot with line width radius function drawDot() { let x = currentPosition[0]; let y = currentPosition[1]; - strokeWeight(currentWidth); + strokeWeight(currentLineWidth); point(x, y); } -function angleIncrement() { - angle += turningAngleIncrement; +// {: Open a polygon +function openPolygon() { + polygonVertices = [[currentPosition[0], currentPosition[1]]]; + polygonOpen = true; } -function angleDecrement() { - angle -= turningAngleIncrement; +// }: Close a polygon and fill it with fill colour +function closePolygon() { + if (polygonOpen && polygonVertices.length > 2) { + fill(100, 150, 255); // Default fill colour + beginShape(); + for (let v of polygonVertices) { + vertex(v[0], v[1]); + } + endShape(CLOSE); + noFill(); // Reset to no fill + } + polygonVertices = []; + polygonOpen = false; +} + +// >: Multiply the line length by the line length scale factor +function multiplyLineLength() { + lineLength *= lineLengthScaleFactor; +} + +// <: Divide the line length by the line length scale factor +function divideLineLength() { + lineLength /= lineLengthScaleFactor; +} + +// &: Swap the meaning of + and - +function swapPlusMinus() { + swapPlusMinusState = !swapPlusMinusState; +} + +// ): Increment turning angle by turning angle increment +function incrementTurningAngle() { + turningAngle += turningAngleIncrement; +} + +// (: Decrement turning angle by turning angle increment +function decrementTurningAngle() { + turningAngle -= turningAngleIncrement; } function draw() { diff --git a/sketches/sketchList.txt b/sketches/sketchList.txt index 7429f71..2c4971b 100644 --- a/sketches/sketchList.txt +++ b/sketches/sketchList.txt @@ -1,2 +1,2 @@ 2images.js, AbstractAlgorithm.js, calmCircles.js, Cubes.js, image.js, -imageNoice.js, labyrinth.js, L-System.js +imageNoice.js, labyrinth.js, L-System.js \ No newline at end of file