fixed and sorted/added comments to L-System

This commit is contained in:
Jürg Hallenbarter
2026-04-27 18:11:48 +00:00
parent 9a9080c155
commit f44a6e6892
5 changed files with 243 additions and 126 deletions

3
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,3 @@
{
"liveServer.settings.port": 5501
}

View File

@@ -30,7 +30,13 @@
const sketches = sketchList.split(','); const sketches = sketchList.split(',');
for (let sketch of sketches) { for (let sketch of sketches) {
const iframe = document.createElement('iframe'); 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 // Apply size if provided
if (sketchSize) { if (sketchSize) {
iframe.style.width = sketchSize + 'px'; iframe.style.width = sketchSize + 'px';
@@ -41,6 +47,8 @@
} }
document.body.appendChild(iframe); document.body.appendChild(iframe);
} }
} else {
console.error('No sketches parameter provided');
} }
</script> </script>
</html> </html>

View File

@@ -4,21 +4,37 @@
<script src="js/p5.js"></script> <script src="js/p5.js"></script>
</head> </head>
<body style="background-color: beige; margin: 0;"> <body style="background-color: beige; margin: 0;">
<script id="sketch"></script> <div id="error" style="color: red; padding: 20px; display: none;"></div>
<script> <script>
const params = new URLSearchParams(window.location.search); const params = new URLSearchParams(window.location.search);
let sketchName = "sketches/" + params.get('sketch'); let sketchName = params.get('sketch');
if (sketchName == "sketches/") { if (!sketchName) {
sketchName = "sketches/" + params.get('sketches'); sketchName = params.get('sketches');
} }
if (sketchName) { if (sketchName) {
console.log(sketchName+" found");
if (!sketchName.endsWith('.js')) { if (!sketchName.endsWith('.js')) {
sketchName += '.js'; sketchName += '.js';
} }
const script = document.getElementById('sketch'); const sketchPath = 'sketches/' + sketchName;
script.src = sketchName; console.log('Loading sketch:', sketchPath);
// Load the sketch directly
const script = document.createElement('script');
script.src = sketchPath;
script.onload = () => {
console.log('Sketch loaded successfully');
};
script.onerror = () => {
console.error('Failed to load sketch:', sketchPath);
document.getElementById('error').style.display = 'block';
document.getElementById('error').textContent = `Error loading sketch: ${sketchName}`;
};
document.head.appendChild(script);
} else {
document.getElementById('error').style.display = 'block';
document.getElementById('error').textContent = 'No sketch specified. Use ?sketch=filename.js';
} }
</script> </script>
</body> </body>
@@ -27,5 +43,16 @@
margin: 0; margin: 0;
overflow: hidden; 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;
}
</style> </style>
</html> </html>

View File

@@ -1,178 +1,257 @@
let angle = 3.141592653589*1.5; /*
let angleDecrement = 1; L-System Fractal Generator
let stepSize = 10;
let widthIncrement = 1; The following characters have a geometric interpretation:
let currentWidth = 1;
let currentPosition = [501 / 2, 500]; Character Meaning
let fractalst = "FF+[+F-F-F]-[-F+F+F]"; F Move forward by line length drawing a line
let stackList = []; f Move forward by line length without drawing a line
let lineLenghtScaleFactor = 1.5; + 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 swapPlusMinusState = false;
let turningAngleIncrement = 0.1; 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() { function setup() {
console.log("setup");
createCanvas(windowWidth, windowHeight); createCanvas(windowWidth, windowHeight);
background(255, 255, 255) background(255, 255, 255);
noFill(); noFill();
stroke(0, 0, 0); stroke(0, 0, 0);
strokeWeight(1); strokeWeight(currentLineWidth);
currentPosition = [width / 2, height]; currentPosition = [width / 2, height - 100];
generateFractal(); generateFractal();
} }
function generateFractal() { function generateFractal() {
for (let i = 0; i < fractalst.length; i++) { for (let i = 0; i < axiom.length; i++) {
let c = fractalst.charAt(i); let c = axiom.charAt(i);
switch (c) { switch (c) {
case "F": case "F":
forward(); moveForwardDraw();
break;
case "+":
plus();
break;
case "-":
minus();
break; break;
case "f": case "f":
forwardNoLine(); moveForwardNoDraw();
break;
case "+":
turnLeft();
break;
case "-":
turnRight();
break; break;
case "|": case "|":
reverseDirection(); reverseDirection();
break; break;
case "#":
lineWidthIncrement();
break;
case "!":
lineWidthDecrement();
break;
case "[": case "[":
pushStack(i); pushState(i);
break; break;
case "]": case "]":
popStack(i); popState(i);
break; break;
case ">": case "#":
lineWidthMultiply(); incrementLineWidth();
break; break;
case "<": case "!":
lineWidthDivide(); decrementLineWidth();
break;
case "&":
swapPlusMinus();
break; break;
case "@": case "@":
drawDot(); drawDot();
break; break;
case "{":
openPolygon();
break;
case "}":
closePolygon();
break;
case ">":
multiplyLineLength();
break;
case "<":
divideLineLength();
break;
case "&":
swapPlusMinus();
break;
case ")": case ")":
angleIncrement(); incrementTurningAngle();
break; break;
case "(": case "(":
angleDecrement(); decrementTurningAngle();
break; break;
default: default:
console.log("unrecognized character",c); // Ignore characters not in the specification (like X)
break; break;
} }
} }
} }
function minus() { // F: Move forward by line length drawing a line
if (swapPlusMinusState) { function moveForwardDraw() {
angle += angleDecrement; let x = currentPosition[0] + cos(angle) * lineLength;
return let y = currentPosition[1] + sin(angle) * lineLength;
} if (polygonOpen) {
angle -= angleDecrement; polygonVertices.push([x, y]);
} } else {
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); line(currentPosition[0], currentPosition[1], x, y);
}
currentPosition = [x, y]; currentPosition = [x, y];
} }
function forwardNoLine(){ // f: Move forward by line length without drawing a line
let x = currentPosition[0] + cos(angle) * stepSize; function moveForwardNoDraw() {
let y = currentPosition[1] + sin(angle) * stepSize; let x = currentPosition[0] + cos(angle) * lineLength;
let y = currentPosition[1] + sin(angle) * lineLength;
currentPosition = [x, y]; currentPosition = [x, y];
} }
function backward() { // +: Turn left by turning angle
let x = currentPosition[0] - cos(angle) * stepSize; function turnLeft() {
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(){
if (swapPlusMinusState) { if (swapPlusMinusState) {
swapPlusMinusState = false; angle -= turningAngle;
return 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() { function drawDot() {
let x = currentPosition[0]; let x = currentPosition[0];
let y = currentPosition[1]; let y = currentPosition[1];
strokeWeight(currentWidth); strokeWeight(currentLineWidth);
point(x, y); point(x, y);
} }
function angleIncrement() { // {: Open a polygon
angle += turningAngleIncrement; function openPolygon() {
polygonVertices = [[currentPosition[0], currentPosition[1]]];
polygonOpen = true;
} }
function angleDecrement() { // }: Close a polygon and fill it with fill colour
angle -= turningAngleIncrement; 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() { function draw() {