From 95215498dd292565522eebb50f235a92c40bce47 Mon Sep 17 00:00:00 2001 From: xnieamo Date: Tue, 7 Feb 2017 20:54:02 -0500 Subject: [PATCH 1/3] everything except iteration done --- src/lsystem.js | 68 ++++++++++++++++++++++++++++++++++++++++++++++++-- src/main.js | 5 ++-- src/turtle.js | 24 +++++++++++++++--- 3 files changed, 90 insertions(+), 7 deletions(-) diff --git a/src/lsystem.js b/src/lsystem.js index e643b6d..2f7a46c 100644 --- a/src/lsystem.js +++ b/src/lsystem.js @@ -7,6 +7,30 @@ function Rule(prob, str) { // TODO: Implement a linked list class and its requisite functions // as described in the homework writeup +var Node = { + symbol : '', + nextNode : null, + prevNode : null +}; + +function LinkedList(){ + this.head = null; + this.tail = null; + this.push = function(val) { + if (!this.head) { + this.head = {symbol: val, nextNode: null, prevNode: null}; + this.tail = this.head; + } else if (this.head == this.tail) { + var newNode = {symbol: val, nextNode: null, prevNode: this.head}; + this.head.nextNode = newNode; + this.tail = newNode; + } else { + var newNode = {symbol: val, nextNode: null, prevNode: this.tail}; + this.tail.nextNode = newNode; + this.tail = newNode; + } + }; +}; // TODO: Turn the string into linked list export function stringToLinkedList(input_string) { @@ -14,19 +38,59 @@ export function stringToLinkedList(input_string) { // you should return a linked list where the head is // at Node('F') and the tail is at Node('X') var ll = new LinkedList(); + for (var i = 0; i < input_string.length; i++) { + ll.push(input_string.charAt(i)); + } + // var thisNode = ll.head; + // for (var i = 0; i < input_string.length; i++) { + // console.log(thisNode.symbol); + // if (thisNode.nextNode){ + // thisNode = thisNode.nextNode; + // } + // } return ll; } // TODO: Return a string form of the LinkedList export function linkedListToString(linkedList) { // ex. Node1("F")->Node2("X") should be "FX" - var result = ""; + var node = linkedList.head; + var result = node.symbol; + + while (node.next) { + node = node.next; + result += node.symbol; + } return result; } // TODO: Given the node to be replaced, // insert a sub-linked-list that represents replacementString function replaceNode(linkedList, node, replacementString) { + var replacementList = stringToLinkedList(replacementString); + if (linkedList.head == linkedList.tail == node) { + linkedList = replacementList; + } + else if (linkedList.head == node) { + var next = node.next; + linkedList.head = replacementList.head; + next.prevNode = replacementList.tail; + replacementList.tail.next = next; + } + else if (linkedList.tail == node) { + var prev = node.prevNode; + linkedList.tail = replacementList.tail; + prev.nextNode = replacementList.head; + replacementList.head.prevNode = prev; + } else { + var next = node.nextNode; + var prev = node.prevNode; + next.prevNode = replacementList.tail; + replacementList.tail.nextNode = next; + + prev.nextNode = replacementList.head; + replacementList.head.nextNode = prev; + } } export default function Lsystem(axiom, grammar, iterations) { @@ -70,7 +134,7 @@ export default function Lsystem(axiom, grammar, iterations) { // The implementation we have provided you just returns a linked // list of the axiom. this.doIterations = function(n) { - var lSystemLL = StringToLinkedList(this.axiom); + var lSystemLL = stringToLinkedList(this.axiom); return lSystemLL; } } \ No newline at end of file diff --git a/src/main.js b/src/main.js index f0c6600..6217523 100644 --- a/src/main.js +++ b/src/main.js @@ -34,7 +34,8 @@ function onLoad(framework) { }); gui.add(lsys, 'axiom').onChange(function(newVal) { - lsys.UpdateAxiom(newVal); + lsys.updateAxiom(newVal); + clearScene(turtle); doLsystem(lsys, lsys.iterations, turtle); }); @@ -54,7 +55,7 @@ function clearScene(turtle) { } function doLsystem(lsystem, iterations, turtle) { - var result = lsystem.DoIterations(iterations); + var result = lsystem.doIterations(iterations); turtle.clear(); turtle = new Turtle(turtle.scene); turtle.renderSymbols(result); diff --git a/src/turtle.js b/src/turtle.js index 1db2723..fd254a7 100644 --- a/src/turtle.js +++ b/src/turtle.js @@ -16,6 +16,7 @@ export default class Turtle { constructor(scene, grammar) { this.state = new TurtleState(new THREE.Vector3(0,0,0), new THREE.Vector3(0,1,0)); this.scene = scene; + this.stack = []; // TODO: Start by adding rules for '[' and ']' then more! // Make sure to implement the functions for the new rules inside Turtle @@ -23,13 +24,28 @@ export default class Turtle { this.renderGrammar = { '+' : this.rotateTurtle.bind(this, 30, 0, 0), '-' : this.rotateTurtle.bind(this, -30, 0, 0), - 'F' : this.makeCylinder.bind(this, 2, 0.1) + 'F' : this.makeCylinder.bind(this, 2, 0.1), + '[' : this.saveState.bind(this), + ']' : this.recoverState.bind(this) }; } else { this.renderGrammar = grammar; } } + saveState() { + // console.log(this.state); + this.stack.push(new TurtleState(this.state.pos, this.state.dir)); + // console.log('push'); + // console.log(this.stack); + // console.log(this.stack.pop()); + + } + + recoverState() { + this.state = this.stack.pop(); + } + // Resets the turtle's position to the origin // and its orientation to the Y axis clear() { @@ -96,17 +112,19 @@ export default class Turtle { // Look in the Turtle's constructor for examples of how to bind // functions to grammar symbols. renderSymbol(symbolNode) { - var func = this.renderGrammar[symbolNode.character]; + var func = this.renderGrammar[symbolNode.symbol]; if (func) { func(); + // this.printState(); } }; // Invoke renderSymbol for every node in a linked list of grammar symbols. renderSymbols(linkedList) { var currentNode; - for(currentNode = linkedList.head; currentNode != null; currentNode = currentNode.next) { + for(currentNode = linkedList.head; currentNode != null; currentNode = currentNode.nextNode) { this.renderSymbol(currentNode); + // console.log(currentNode.symbol); } } } \ No newline at end of file From 5cb0bc488fca3c13b1ab477274e782ab1dc2e0f6 Mon Sep 17 00:00:00 2001 From: xnieamo Date: Tue, 7 Feb 2017 21:28:39 -0500 Subject: [PATCH 2/3] lsystem done, need to add features now --- src/lsystem.js | 43 ++++++++++++++++++++++++++++++------------- src/main.js | 39 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 67 insertions(+), 15 deletions(-) diff --git a/src/lsystem.js b/src/lsystem.js index 2f7a46c..2ce1afb 100644 --- a/src/lsystem.js +++ b/src/lsystem.js @@ -41,13 +41,6 @@ export function stringToLinkedList(input_string) { for (var i = 0; i < input_string.length; i++) { ll.push(input_string.charAt(i)); } - // var thisNode = ll.head; - // for (var i = 0; i < input_string.length; i++) { - // console.log(thisNode.symbol); - // if (thisNode.nextNode){ - // thisNode = thisNode.nextNode; - // } - // } return ll; } @@ -55,11 +48,11 @@ export function stringToLinkedList(input_string) { export function linkedListToString(linkedList) { // ex. Node1("F")->Node2("X") should be "FX" var node = linkedList.head; - var result = node.symbol; - - while (node.next) { - node = node.next; - result += node.symbol; + var result = ''; + + while (node) { + result = result.concat(node.symbol); + node = node.nextNode; } return result; } @@ -91,6 +84,7 @@ function replaceNode(linkedList, node, replacementString) { prev.nextNode = replacementList.head; replacementList.head.nextNode = prev; } + return replacementList.tail.next; } export default function Lsystem(axiom, grammar, iterations) { @@ -128,13 +122,36 @@ export default function Lsystem(axiom, grammar, iterations) { } } + this.updateString = function(n) { + var stringResult = this.axiom; + + for (var i = 0; i < n; i++) { + var newString = ''; + for (var j = 0; j < stringResult.length; j++) { + var currentChar = stringResult.charAt(j); + if (this.grammar[currentChar]) { + newString = newString.concat(this.grammar[currentChar][0].successorString); + } else { + newString = newString.concat(currentChar); + } + } + stringResult = newString; + } + + // console.log(stringResult); + return stringResult; + } + + // TODO // This function returns a linked list that is the result // of expanding the L-system's axiom n times. // The implementation we have provided you just returns a linked // list of the axiom. this.doIterations = function(n) { - var lSystemLL = stringToLinkedList(this.axiom); + + var lSystemLL = stringToLinkedList(this.updateString(n)); + return lSystemLL; } } \ No newline at end of file diff --git a/src/main.js b/src/main.js index 6217523..e1aa001 100644 --- a/src/main.js +++ b/src/main.js @@ -6,6 +6,40 @@ import Turtle from './turtle.js' var turtle; +function rate_limit(func) { + var running = false; + var next = undefined; + + function onDone() { + running = false; // set the flag to allow the function to be called again + if (typeof next !== 'undefined') { + callFunc(next); // call the function again with the queued args + } + } + + function callFunc(args) { + if (running) { + // if the function is already running, remember the arguments passed in so we can call the func with them after we're ready + next = args; + } else { + running = true; // prevent other function calls from running until we're done + next = undefined; + func.apply(func, args); // call the func with the arguments + } + } + + // return a new function wrapping the function we want to rate limit + return function() { + // we use the same arguments but add the onDone callback as the last argument + var args = new Array(arguments.length + 1); + for (var i = 0; i < arguments.length; ++i) { + args[i] = arguments[i]; + } + args[arguments.length] = onDone; + callFunc(args); + } +} + // called after the scene loads function onLoad(framework) { var scene = framework.scene; @@ -39,10 +73,11 @@ function onLoad(framework) { doLsystem(lsys, lsys.iterations, turtle); }); - gui.add(lsys, 'iterations', 0, 12).step(1).onChange(function(newVal) { + gui.add(lsys, 'iterations', 0, 12).step(1).onChange(rate_limit(function(newVal, done) { clearScene(turtle); doLsystem(lsys, newVal, turtle); - }); + done(); + })); } // clears the scene by removing all geometries added by turtle.js From 1eae65d23d82626c3badb5594808d847ef707fc6 Mon Sep 17 00:00:00 2001 From: xnieamo Date: Wed, 8 Feb 2017 00:00:25 -0500 Subject: [PATCH 3/3] some basic interactions --- src/main.js | 11 +++++++++++ src/turtle.js | 16 +++++++++------- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/main.js b/src/main.js index e1aa001..bf5f420 100644 --- a/src/main.js +++ b/src/main.js @@ -6,6 +6,10 @@ import Turtle from './turtle.js' var turtle; +var settings = { + angle : 30 +} + function rate_limit(func) { var running = false; var next = undefined; @@ -78,6 +82,11 @@ function onLoad(framework) { doLsystem(lsys, newVal, turtle); done(); })); + + gui.add(settings,'angle', 0, 90).onChange(function(newVal) { + clearScene(turtle); + doLsystem(lsys, lsys.iterations, turtle); + }); } // clears the scene by removing all geometries added by turtle.js @@ -93,6 +102,8 @@ function doLsystem(lsystem, iterations, turtle) { var result = lsystem.doIterations(iterations); turtle.clear(); turtle = new Turtle(turtle.scene); + turtle.angle = settings.angle; + turtle.updateAngles(); turtle.renderSymbols(result); } diff --git a/src/turtle.js b/src/turtle.js index fd254a7..608e3da 100644 --- a/src/turtle.js +++ b/src/turtle.js @@ -17,13 +17,14 @@ export default class Turtle { this.state = new TurtleState(new THREE.Vector3(0,0,0), new THREE.Vector3(0,1,0)); this.scene = scene; this.stack = []; + this.angle = 30; // TODO: Start by adding rules for '[' and ']' then more! // Make sure to implement the functions for the new rules inside Turtle if (typeof grammar === "undefined") { this.renderGrammar = { - '+' : this.rotateTurtle.bind(this, 30, 0, 0), - '-' : this.rotateTurtle.bind(this, -30, 0, 0), + '+' : this.rotateTurtle.bind(this, this.angle, 0, 0), + '-' : this.rotateTurtle.bind(this, -this.angle, 0, 0), 'F' : this.makeCylinder.bind(this, 2, 0.1), '[' : this.saveState.bind(this), ']' : this.recoverState.bind(this) @@ -34,18 +35,18 @@ export default class Turtle { } saveState() { - // console.log(this.state); this.stack.push(new TurtleState(this.state.pos, this.state.dir)); - // console.log('push'); - // console.log(this.stack); - // console.log(this.stack.pop()); - } recoverState() { this.state = this.stack.pop(); } + updateAngles() { + this.renderGrammar['+'] = this.rotateTurtle.bind(this, this.angle, 0, 0); + this.renderGrammar['-'] = this.rotateTurtle.bind(this, -this.angle, 0, 0); + } + // Resets the turtle's position to the origin // and its orientation to the Y axis clear() { @@ -62,6 +63,7 @@ export default class Turtle { // Rotate the turtle's _dir_ vector by each of the // Euler angles indicated by the input. rotateTurtle(x, y, z) { + // console.log(this.angle); var e = new THREE.Euler( x * 3.14/180, y * 3.14/180,