diff --git a/README.md b/README.md index 5ca56be..f793436 100644 --- a/README.md +++ b/README.md @@ -1,67 +1,40 @@ The objective of this assignment is to create an L System parser and generate interesting looking plants. Start by forking and then cloning this repository: [https://github.com/CIS700-Procedural-Graphics/Project3-LSystems](https://github.com/CIS700-Procedural-Graphics/Project3-LSystems) -# L-System Parser +# Final Results -lsystem.js contains classes for L-system, Rule, and LinkedList. Here’s our suggested structure: +Raining Christmas (with all these falling apples, we'll have more Newtons poppin' up in no time!): -**The Symbol Nodes/Linked List:** +![alt text](https://github.com/MegSesh/Project3-LSystems/blob/master/final_results/9.png "Image 1") -Rather than representing our symbols as a string like in many L-system implementations, we prefer to use a linked list. This allows us to store additional information about each symbol at time of parsing (e.g. what iteration was this symbol added in?) Since we’re adding and replacing symbols at each iteration, we also save on the overhead of creating and destroying strings, since linked lists of course make it easy to add and remove nodes. You should write a Linked List class with Nodes that contain at least the following information: -- The next node in the linked list -- The previous node in the linked list -- The grammar symbol at theis point in the overal string +1. Image 1: +![alt text](https://github.com/MegSesh/Project3-LSystems/blob/master/final_results/1.png "Image 1") -We also recommend that you write the following functions to interact with your linked list: -- A function to symmetrically link two nodes together (e.g. Node A’s next is Node B, and Node B’s prev is Node A) -- A function to expand one of the symbol nodes of the linked list by replacing it with several new nodes. This function should look at the list of rules associated with the symbol in the linked list’s grammar dictionary, then generate a uniform random number between 0 and 1 in order to determine which of the Rules should be used to expand the symbol node. You will refer to a Rule’s probability and compare it to your random number in order to determine which Rule should be chosen. +2. Image 2: +![alt text](https://github.com/MegSesh/Project3-LSystems/blob/master/final_results/2.png "Image 2") -**Rules:** -These are containers for the preconditions, postconditions and probability of a single replacement operation. They should operate on a symbol node in your linked list. +3. Image 3: +![alt text](https://github.com/MegSesh/Project3-LSystems/blob/master/final_results/3.png "Image 3") -**L-system:** -This is the parser, which will loop through your linked list of symbol nodes and apply rules at each iteration. +4. Image 4: +![alt text](https://github.com/MegSesh/Project3-LSystems/blob/master/final_results/4.png "Image 4") -Implement the following functions in L-System so that you can apply grammar rules to your axiom given some number of iterations. More details and implementation suggestions about functions can be found in the TODO comments -- `stringToLinkedList(input_string)` -- `linkedListToString(linkedList)` -- `replaceNode(linkedList, node, replacementString)` -- `doIterations(num)` +5. Image 5: +![alt text](https://github.com/MegSesh/Project3-LSystems/blob/master/final_results/5.png "Image 5") -## Turtle -`turtle.js` has a function called renderSymbol that takes in a single node of a linked list and performs an operation to change the turtle’s state based on the symbol contained in the node. Usually, the turtle’s change in state will result in some sort of rendering output, such as drawing a cylinder when the turtle moves forward. We have provided you with a few example functions to illustrate how to write your own functions to be called by renderSymbol; these functions are rotateTurtle, moveTurtle, moveForward, and makeCylinder. If you inspect the constructor of the Turtle class, you can see how to associate an operation with a grammar symbol. +6. Image 6: +![alt text](https://github.com/MegSesh/Project3-LSystems/blob/master/final_results/6.png "Image 6") -- Modify turtle.js to support operations associated with the symbols `[` and `]` - - When you parse `[` you need to store the current turtle state somewhere - - When you parse `]` you need to set your turtle’s state to the most recently stored state. Think of this a pushing and popping turtle states on and off a stack. For example, given `F[+F][-F]`, the turtle should draw a Y shape. Note that your program must be capable of storing many turtle states at once in a stack. -- In addition to operations for `[` and `]`, you must invent operations for any three symbols of your choosing. +7. Image 7: +![alt text](https://github.com/MegSesh/Project3-LSystems/blob/master/final_results/7.png "Image 7") -## Interactivity - -Using dat.GUI and the examples provided in the reference code, make some aspect of your demo an interactive variable. For example, you could modify: - -1. the axiom -2. Your input grammer rules and their probability -3. the angle of rotation of the turtle -4. the size or color or material of the cylinder the turtle draws, etc! - -## L-System Plants - -Design a grammar for a new procedural plant! As the preceding parts of this assignment are basic computer science tasks, this is where you should spend the bulk of your time on this assignment. Come up with new grammar rules and include screenshots of your plants in your README. For inspiration, take a look at Example 7: Fractal Plant in Wikipedia: https://en.wikipedia.org/wiki/L-system Your procedural plant must have the following features - -1. Grow in 3D. Take advantage of three.js! -2. Have flowers or leaves that are added as a part of the grammar -3. Variation. Different instances of your plant should look distinctly different! -4. A twist. Broccoli trees are cool and all, but we hope to see sometime a little more surprising in your grammars - -# Publishing Your code - -Running `npm run deploy` will automatically build your project and push it to gh-pages where it will be visible at `username.github.io/repo-name`. NOTE: You MUST commit AND push all changes to your MASTER branch before doing this or you may lose your work. The `git` command must also be available in your terminal or command prompt. If you're using Windows, it's a good idea to use Git Bash. \ No newline at end of file +8. Image 8: +![alt text](https://github.com/MegSesh/Project3-LSystems/blob/master/final_results/8.png "Image 8") diff --git a/README_old.md b/README_old.md new file mode 100644 index 0000000..b05957f --- /dev/null +++ b/README_old.md @@ -0,0 +1,67 @@ + +The objective of this assignment is to create an L System parser and generate interesting looking plants. Start by forking and then cloning this repository: [https://github.com/CIS700-Procedural-Graphics/Project3-LSystems](https://github.com/CIS700-Procedural-Graphics/Project3-LSystems) + +# L-System Parser + +lsystem.js contains classes for L-system, Rule, and LinkedList. Here’s our suggested structure: + +**The Symbol Nodes/Linked List:** + +Rather than representing our symbols as a string like in many L-system implementations, we prefer to use a linked list. This allows us to store additional information about each symbol at time of parsing (e.g. what iteration was this symbol added in?) Since we’re adding and replacing symbols at each iteration, we also save on the overhead of creating and destroying strings, since linked lists of course make it easy to add and remove nodes. You should write a Linked List class with Nodes that contain at least the following information: + +- The next node in the linked list +- The previous node in the linked list +- The grammar symbol at theis point in the overal string + +We also recommend that you write the following functions to interact with your linked list: + +- A function to symmetrically link two nodes together (e.g. Node A’s next is Node B, and Node B’s prev is Node A) +- A function to expand one of the symbol nodes of the linked list by replacing it with several new nodes. This function should look at the list of rules associated with the symbol in the linked list’s grammar dictionary, then generate a uniform random number between 0 and 1 in order to determine which of the Rules should be used to expand the symbol node. You will refer to a Rule’s probability and compare it to your random number in order to determine which Rule should be chosen. + +**Rules:** + +These are containers for the preconditions, postconditions and probability of a single replacement operation. They should operate on a symbol node in your linked list. + +**L-system:** + +This is the parser, which will loop through your linked list of symbol nodes and apply rules at each iteration. + +Implement the following functions in L-System so that you can apply grammar rules to your axiom given some number of iterations. More details and implementation suggestions about functions can be found in the TODO comments + +- `stringToLinkedList(input_string)` +- `linkedListToString(linkedList)` +- `replaceNode(linkedList, node, replacementString)` +- `doIterations(num)` + +## Turtle + +`turtle.js` has a function called renderSymbol that takes in a single node of a linked list and performs an operation to change the turtle’s state based on the symbol contained in the node. Usually, the turtle’s change in state will result in some sort of rendering output, such as drawing a cylinder when the turtle moves forward. We have provided you with a few example functions to illustrate how to write your own functions to be called by renderSymbol; these functions are rotateTurtle, moveTurtle, moveForward, and makeCylinder. If you inspect the constructor of the Turtle class, you can see how to associate an operation with a grammar symbol. + +- Modify turtle.js to support operations associated with the symbols `[` and `]` + - When you parse `[` you need to store the current turtle state somewhere + - When you parse `]` you need to set your turtle’s state to the most recently stored state. Think of this a pushing and popping turtle states on and off a stack. For example, given `F[+F][-F]`, the turtle should draw a Y shape. Note that your program must be capable of storing many turtle states at once in a stack. + +- In addition to operations for `[` and `]`, you must invent operations for any three symbols of your choosing. + + +## Interactivity + +Using dat.GUI and the examples provided in the reference code, make some aspect of your demo an interactive variable. For example, you could modify: + +1. the axiom +2. Your input grammer rules and their probability +3. the angle of rotation of the turtle +4. the size or color or material of the cylinder the turtle draws, etc! + +## L-System Plants + +Design a grammar for a new procedural plant! As the preceding parts of this assignment are basic computer science tasks, this is where you should spend the bulk of your time on this assignment. Come up with new grammar rules and include screenshots of your plants in your README. For inspiration, take a look at Example 7: Fractal Plant in Wikipedia: https://en.wikipedia.org/wiki/L-system Your procedural plant must have the following features + +1. Grow in 3D. Take advantage of three.js! +2. Have flowers or leaves that are added as a part of the grammar +3. Variation. Different instances of your plant should look distinctly different! +4. A twist. Broccoli trees are cool and all, but we hope to see sometime a little more surprising in your grammars + +# Publishing Your code + +Running `npm run deploy` will automatically build your project and push it to gh-pages where it will be visible at `username.github.io/repo-name`. NOTE: You MUST commit AND push all changes to your MASTER branch before doing this or you may lose your work. The `git` command must also be available in your terminal or command prompt. If you're using Windows, it's a good idea to use Git Bash. diff --git a/final_results/1.png b/final_results/1.png new file mode 100644 index 0000000..2d5dd0e Binary files /dev/null and b/final_results/1.png differ diff --git a/final_results/2.png b/final_results/2.png new file mode 100644 index 0000000..b4d6417 Binary files /dev/null and b/final_results/2.png differ diff --git a/final_results/3.png b/final_results/3.png new file mode 100644 index 0000000..e05793e Binary files /dev/null and b/final_results/3.png differ diff --git a/final_results/4.png b/final_results/4.png new file mode 100644 index 0000000..1b5f25b Binary files /dev/null and b/final_results/4.png differ diff --git a/final_results/5.png b/final_results/5.png new file mode 100644 index 0000000..348bbe4 Binary files /dev/null and b/final_results/5.png differ diff --git a/final_results/6.png b/final_results/6.png new file mode 100644 index 0000000..644e3d9 Binary files /dev/null and b/final_results/6.png differ diff --git a/final_results/7.png b/final_results/7.png new file mode 100644 index 0000000..49cda21 Binary files /dev/null and b/final_results/7.png differ diff --git a/final_results/8.png b/final_results/8.png new file mode 100644 index 0000000..83e033f Binary files /dev/null and b/final_results/8.png differ diff --git a/final_results/9.png b/final_results/9.png new file mode 100644 index 0000000..6ccf903 Binary files /dev/null and b/final_results/9.png differ diff --git a/src/lsystem.js b/src/lsystem.js index e643b6d..adcad6f 100644 --- a/src/lsystem.js +++ b/src/lsystem.js @@ -1,76 +1,302 @@ +//======================================================== RULE CLASS =============================================================== // A class that represents a symbol replacement rule to // be used when expanding an L-system grammar. function Rule(prob, str) { this.probability = prob; // The probability that this Rule will be used when replacing a character in the grammar string this.successorString = str; // The string that will replace the char that maps to this Rule -} +}//end Rule class + + + + +/* //=================================================== LINKED LIST & NODE CLASSES ============================================================ +You should write a Linked List class with Nodes that contain at least the following information: + + - The next node in the linked list + - The previous node in the linked list + - The grammar symbol at this point in the overall string + +We also recommend that you write the following functions to interact with your linked list: + +- A function to symmetrically link two nodes together (e.g. Node A’s next is Node B, and Node B’s prev is Node A) + +- A function to expand one of the symbol nodes of the linked list by replacing it with several new nodes. + This function should look at the list of rules associated with the symbol in the linked list’s grammar dictionary, + then generate a uniform random number between 0 and 1 in order to determine which of the Rules should be used + to expand the symbol node. You will refer to a Rule’s probability and compare it to your random number in order + to determine which Rule should be chosen. + (NOTE: THIS IS ESSENTIALLY JUST REPLACENODE) +*/ + +function Node(gramSym, i) { + this.previous = null; + this.next = null; + this.grammarSym = gramSym; + this.index = i; + //this.replaceable = replaceBool; + + this.linkNodes = function(nodeA, nodeB) { + //nodeA.next = nodeB; + nodeA.next = nodeB; + //nodeB.previous = nodeA; + nodeB.previous = nodeA; + }//end linkNodes function + +}//end Node class + +function LinkedList() { + this.head = null; + this.tail = null; + this._length = 0; +}//end LinkedList class + + + + +//=================================================== EXTERNAL FUNCTIONS ========================================================== // TODO: Implement a linked list class and its requisite functions // as described in the homework writeup -// TODO: Turn the string into linked list -export function stringToLinkedList(input_string) { +// TODO: Turn the string into linked list +export function StringToLinkedList(input_string) { // ex. assuming input_string = "F+X" - // you should return a linked list where the head is + // you should return a linked list where the head is // at Node('F') and the tail is at Node('X') + //console.log(input_string); + //console.log(input_string.length); + var ll = new LinkedList(); + + var headNode = new Node(input_string.charAt(0), 0); + //console.log(input_string.charAt(0)); //THIS GIVES ME F + + ll.head = headNode; + ll._length++; + + var currNode = headNode; + + for(var x = 1; x < input_string.length; x++) + { + var currSym = input_string.charAt(x); + //console.log(input_string.charAt(x)); + + var newNode = new Node(currSym, x) + + currNode.next = newNode; + newNode.previous = currNode; + currNode = newNode; + ll._length++; + }//end for x + + ll.tail = currNode; //curr should be the last one technically + return ll; } + // TODO: Return a string form of the LinkedList -export function linkedListToString(linkedList) { +export function LinkedListToString(linkedList) { // ex. Node1("F")->Node2("X") should be "FX" var result = ""; + var currSym = ""; + + var currNode = linkedList.head; + var nextNode = currNode.next; + + while(nextNode != null) + { + currSym = currNode.grammarSym; + result += currSym; + nextNode = nextNode.next; + } + return result; } -// TODO: Given the node to be replaced, +// TODO: Given the node to be replaced, // insert a sub-linked-list that represents replacementString function replaceNode(linkedList, node, replacementString) { -} + //what to do with replacement string + //find what rule to do + //maybe you have a function called applyrandom rule + //returns rule you need to implement + //rule has a successor string + //use that string, make a linked list out of it, and use that to replace the node + + //cut out node and replace with linked list you get from return of stringToLinkedList + + var currNodePrev = node.previous; + var currNodeNext = node.next; + + var subLL = StringToLinkedList(replacementString); + var replaceNodeHead = subLL.head; + var replaceNodeTail = subLL.tail; + + + //node is at head of linkedlist + if(node.previous === null) + { + replaceNodeHead.previous = null; + linkedList.head = replaceNodeHead; + } + else { + currNodePrev.next = replaceNodeHead; + replaceNodeHead.previous = currNodePrev; + } + + //if node is at tail of linkedlist + if(node.next === null) + { + replaceNodeTail.next = null; + linkedList.tail = replaceNodeTail; + } + else{ + currNodeNext.previous = replaceNodeTail; + replaceNodeTail.next = currNodeNext; + } + +}//end replace node function + + + + +//=================================================== LSYSTEM CLASS ============================================================== export default function Lsystem(axiom, grammar, iterations) { // default LSystem - this.axiom = "FX"; + this.axiom = "FX";//"FFX";//FX this.grammar = {}; - this.grammar['X'] = [ - new Rule(1.0, '[-FX][+FX]') + this.grammar['X'] = [//'X'] = [ + new Rule(1.0, 'FF-[-F+F+S+FX]+[+F-F-S-FX]X'),//'F[RX][LX][SX]FX') + new Rule(0.4, 'F[RX][LX][SX]FX') //change this between 0.1 and 0.7 + + //change axiom + //change rotation + + + /* Cool looking sword like tree + this.axiom = "FFFX"; + this.grammar = {}; + this.grammar['X'] = [ + new Rule(1.0, 'F[RX][LX]FX')*/ + + /* new Rule(0.7, '[-FX][+FX]'), + new Rule(0.3,'FF-[-F+RX]+[-F+RX]')*/ + + /* new Rule(0.3, '[-FX][+FX]'), + new Rule(0.7,'FF-[-F-LX]+[-F+RX]')*/ + + + //FF-[-F-L]+[-F-F+R] --> bigger creepy hand + //FF-[-F-L]+[-F+R] --> creepy hand + //FFF-[-F+F-L]+[+F-F+R] + //FFF-[-F+F-L]+[+F-F-R] + //FF-[-F+F+L]+[+F-F-R]' + //Side tree: F=FF-[-F+F+F]+[+F-F-F] + //[FF-FX][+FRX][-FLX] + //'FFF[-X][+RX][-LX]' + ]; - this.iterations = 0; - + this.iterations = 0; + this.randomVal = 0.1; + // Set up the axiom string if (typeof axiom !== "undefined") { this.axiom = axiom; } - // Set up the grammar as a dictionary that + // Set up the grammar as a dictionary that // maps a single character (symbol) to a Rule. if (typeof grammar !== "undefined") { this.grammar = Object.assign({}, grammar); } - - // Set up iterations (the number of times you + + // Set up iterations (the number of times you // should expand the axiom in DoIterations) if (typeof iterations !== "undefined") { this.iterations = iterations; } - // A function to alter the axiom string stored + // A function to alter the axiom string stored // in the L-system this.updateAxiom = function(axiom) { // Setup axiom if (typeof axiom !== "undefined") { this.axiom = axiom; } + }//end updateAxiom function + + this.updateRandomVal = function(randVal) { + if(typeof randVal !== "undefined") { + this.grammar['X'] = [//'X'] = [ + new Rule(1.0, 'FF-[-F+F+S+FX]+[+F-F-S-FX]X'), + new Rule(randVal, 'F[RX][LX][SX]FX')]; + } } // TODO - // This function returns a linked list that is the result + // 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) { + this.DoIterations = function(n) { var lSystemLL = StringToLinkedList(this.axiom); + + //iterate through every node in linked list, call replacenode + //add "replaceable" flag for each node + //only call replacenode if node is replaceable + + //for each node that is replacebale, call replacenode + //but, the grammarstring input is the return of another function/ + //implement this function which does + //look through grammar array + for(var r = 0; r < n; r++) + { + var currNode = lSystemLL.head; + + while(currNode !== null) + { + var nextOfCurrSym = currNode.next; + var currSym = currNode.grammarSym; + var rulesArray = this.grammar[currSym]; + + if(typeof rulesArray !== "undefined") + { + var replacementStr = ""; + + var randomVal = Math.random(); //returns value between [0, 1) + var ProbVal1 = rulesArray[0].probability; + var ProbVal2 = rulesArray[1].probability; + + if(randomVal < ProbVal1 && randomVal > ProbVal2) + { + replacementStr = rulesArray[0].successorString; + } + else { + replacementStr = rulesArray[1].successorString; + } + + //THIS DOESNT WORK FOR SOME REASON + // var currTotal = 0.0; + // console.log(randomVal); + // //iterate through the array of rules for this currSym + // for(var x = 0; x < rulesArray.length; x++) + // { + // var currProbVal = rulesArray[x].probability + // currTotal += currProbVal; + // if(randomVal < currTotal) + // { + // replacementStr = rulesArray[x].successorString; + // }//end if + // }//end for loop + + replaceNode(lSystemLL, currNode, replacementStr); + + }//end if currsym is in dictionary + currNode = nextOfCurrSym; + }//end while loop + }//end for loop return lSystemLL; - } -} \ No newline at end of file + }//end doIterations function +}//end LSystem Class diff --git a/src/main.js b/src/main.js index f0c6600..73f8817 100644 --- a/src/main.js +++ b/src/main.js @@ -34,15 +34,62 @@ function onLoad(framework) { }); gui.add(lsys, 'axiom').onChange(function(newVal) { - lsys.UpdateAxiom(newVal); + lsys.updateAxiom(newVal); doLsystem(lsys, lsys.iterations, turtle); }); - gui.add(lsys, 'iterations', 0, 12).step(1).onChange(function(newVal) { + gui.add(lsys, 'iterations', 0, 5).step(1).onChange(function(newVal) { clearScene(turtle); doLsystem(lsys, newVal, turtle); }); -} + + //call toonshader function with new offset + //call dolsystem + + gui.add(lsys, 'randomVal', 0.1, 0.7).onChange(function(newVal) { + //make function in lsystem to change randomval + lsys.updateRandomVal(newVal); + doLsystem(lsys, lsys.iterations, turtle); + }) + + gui.add(turtle, 'angle', 10, 80).onChange(function(newVal) { + //make function in lsystem to change randomval + //lsys.updateRandomVal(newVal); + turtle.updateAngle(newVal); + doLsystem(lsys, lsys.iterations, turtle); + }) + + gui.add(turtle, 'cylinderWidth', 0.1, 0.6).onChange(function(newVal) { + //make function in lsystem to change randomval + //lsys.updateRandomVal(newVal); + turtle.updateCylinderWidth(newVal); + doLsystem(lsys, lsys.iterations, turtle); + }) + + + //SOMETHING IS UP WITH THE COLOR. HOW DO I INCORPORATE BOTH THE COLOR PICKER AND CHANGING COLOR IN TURTLE + // var colorChanger = function() { + // this.branchColor = "#ffae23"; // CSS string + // // this.color1 = [ 0, 128, 255 ]; // RGB array + // // this.color2 = [ 0, 128, 255, 0.3 ]; // RGB with alpha + // // this.color3 = { h: 350, s: 0.9, v: 0.3 }; // Hue, saturation, value + // + // turtle.updateBranchColor(this.branchColor); + // doLsystem(lsys, lsys.iterations, turtle); + // }; + // var text = new colorChanger(); + // gui.addColor(text, 'branchColor'); + // + // + // gui.add(turtle, 'branchColor', 0x00cccc, 0xfff000).onChange(function(newVal) { + // turtle.updateBranchColor(newVal); + // doLsystem(lsys, lsys.iterations, turtle); + // }) + + + +}//end onload function + // clears the scene by removing all geometries added by turtle.js function clearScene(turtle) { diff --git a/src/turtle.js b/src/turtle.js index 1db2723..73d1f10 100644 --- a/src/turtle.js +++ b/src/turtle.js @@ -10,12 +10,23 @@ var TurtleState = function(pos, dir) { dir: new THREE.Vector3(dir.x, dir.y, dir.z) } } - + + +//turtleStateStack.push() +//turtleStateStack.push() +//array is now [value1, value2] +// var i = turtleStateStack.pop() +//i = value2 + 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.turtleStateStack = []; + this.angle = 10; + this.branchColor = 0x00cccc; + this.cylinderWidth = 0.1; // TODO: Start by adding rules for '[' and ']' then more! // Make sure to implement the functions for the new rules inside Turtle @@ -23,17 +34,44 @@ 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.branchColor), + 'F' : this.makeCylinder.bind(this, 2, this.cylinderWidth, this.branchColor), + '[' : this.saveState.bind(this), + ']' : this.setState.bind(this), + //'R' : this.rotateTurtle.bind(this, 45, 0, 0), + 'R' : this.rotateTurtle.bind(this, this.angle, 0, 0), + 'L' : this.rotateTurtle.bind(this, -this.angle, 0, 0), + 'S' : this.makeSphere.bind(this, 1, 5) }; } else { this.renderGrammar = grammar; } } + //updates angle of symbols R and L + updateAngle(angle) { + if(typeof angle !== "undefined") { + this.angle = angle; + } + } + + updateBranchColor(color) { + if(typeof color !== "undefined") { + this.branchColor = color; + } + } + + updateCylinderWidth(new_width) { + if(typeof new_width !== "undefined") { + this.cylinderWidth = new_width; + } + } + + // Resets the turtle's position to the origin // and its orientation to the Y axis clear() { - this.state = new TurtleState(new THREE.Vector3(0,0,0), new THREE.Vector3(0,1,0)); + this.state = new TurtleState(new THREE.Vector3(0,0,0), new THREE.Vector3(0,1,0)); } // A function to help you debug your turtle functions @@ -43,7 +81,7 @@ export default class Turtle { console.log(this.state.dir) } - // Rotate the turtle's _dir_ vector by each of the + // Rotate the turtle's _dir_ vector by each of the // Euler angles indicated by the input. rotateTurtle(x, y, z) { var e = new THREE.Euler( @@ -65,12 +103,16 @@ export default class Turtle { var newVec = this.state.dir.multiplyScalar(dist); this.state.pos.add(newVec); }; - + // Make a cylinder of given length and width starting at turtle pos // Moves turtle pos ahead to end of the new cylinder - makeCylinder(len, width) { + makeCylinder(len, width, color) { + + //console.log("IM IN MAKE CYLLINDER"); + var geometry = new THREE.CylinderGeometry(width, width, len); - var material = new THREE.MeshBasicMaterial( {color: 0x00cccc} ); + //var material = new THREE.MeshBasicMaterial( {color: 0x00cccc} ); + var material = new THREE.MeshBasicMaterial( {color: color} ); var cylinder = new THREE.Mesh( geometry, material ); this.scene.add( cylinder ); @@ -91,12 +133,71 @@ export default class Turtle { //Scoot the turtle forward by len units this.moveForward(len/2); }; - + + //When you parse [ you need to store the current turtle state somewhere + saveState() { + this.turtleStateStack.push(new TurtleState(this.state.pos, this.state.dir)); + }; + + /* When you parse ] you need to set your turtle’s state to the most recently stored state. + Think of this a pushing and popping turtle states on and off a stack. + For example, given F[+F][-F], the turtle should draw a Y shape. + Note that your program must be capable of storing many turtle states at once in a stack. + */ + setState() { + this.state = this.turtleStateStack.pop(); + }; + + + makeSphere(radius, width) { + var geometry = new THREE.SphereGeometry(radius, width, width); + var material = new THREE.MeshBasicMaterial( {color: 0xff0000} ); + //var material = toonShader(0.5); //NEED TO ASK AUSTIN ABOUT CONSTRUCTOR FIX + + var color1 = 0xfff000; + var color2 = 0xff0000; + var green = 0x32CD32; + var randVal = Math.random(); + if(randVal <= 0.3) + { + material = new THREE.MeshBasicMaterial( {color: color1} ); + } + else if(randVal <= 0.6 && randVal > 0.3) + { + material = new THREE.MeshBasicMaterial( {color: green} ); + } + else { + material = new THREE.MeshBasicMaterial( {color: color2} ); + } + + var sphere = new THREE.Mesh( geometry, material ); + this.scene.add( sphere ); + + + //Orient the sphere to the turtle's current direction + var quat = new THREE.Quaternion(); + quat.setFromUnitVectors(new THREE.Vector3(0,1,0), this.state.dir); + var mat4 = new THREE.Matrix4(); + mat4.makeRotationFromQuaternion(quat); + sphere.applyMatrix(mat4); + + + //Move the sphere so its base rests at the turtle's current position + var mat5 = new THREE.Matrix4(); + var trans = this.state.pos.add(this.state.dir.multiplyScalar(0.5 * width)); + mat5.makeTranslation(trans.x, trans.y, trans.z); + sphere.applyMatrix(mat5); + + //Scoot the turtle forward by len units + this.moveForward(width/2); + } + // Call the function to which the input symbol is bound. - // Look in the Turtle's constructor for examples of how to bind + // Look in the Turtle's constructor for examples of how to bind // functions to grammar symbols. renderSymbol(symbolNode) { - var func = this.renderGrammar[symbolNode.character]; + //console.log("IM IN RENDER SYMBOLS"); + var func = this.renderGrammar[symbolNode.grammarSym];//character]; if (func) { func(); } @@ -109,4 +210,33 @@ export default class Turtle { this.renderSymbol(currentNode); } } -} \ No newline at end of file +}//end turtle class + + +function toonShader(colorOffset) { + var toonGreenMaterial; + var stepSize = 1.0/5.0; + + for ( var alpha = 0, alphaIndex = 0; alpha <= 1.0; alpha += stepSize, alphaIndex ++ ) { + var specularShininess = Math.pow(2.0 , alpha * 10.0 ); + + for ( var beta = 0; beta <= 1.0; beta += stepSize ) { + var specularColor = new THREE.Color( beta * 0.2, beta * 0.2, beta * 0.2 ); + + for ( var gamma = 0; gamma <= 1.0; gamma += stepSize ) { + var offset = colorOffset; + var diffuseColor = new THREE.Color().setHSL( alpha * offset, 0.5, gamma * 0.5 ).multiplyScalar( 1.0 - beta * 0.2 ); + + toonGreenMaterial = new THREE.MeshToonMaterial( { + color: diffuseColor, + specular: specularColor, + reflectivity: beta, + shininess: specularShininess, + shading: THREE.SmoothShading + } );//end var toon material + }//end for gamma + }//end for beta + }//end for alpha + + return toonGreenMaterial; +}