Skip to content

Instantly share code, notes, and snippets.

@GyrosOfWar
Last active December 17, 2015 22:19
Show Gist options
  • Save GyrosOfWar/5680942 to your computer and use it in GitHub Desktop.
Save GyrosOfWar/5680942 to your computer and use it in GitHub Desktop.
package at.wambo.lsystem
import org.jsfml.graphics.VertexArray
/**
* User: Martin
* Date: 27.05.13
* Time: 16:50
*/
class LSystem(private val axiom: String,
private val iterations: Int,
private val angle: Double,
private val distance: Int,
val xSize: Int,
val ySize: Int)
(val rules: PartialFunction[Char, String]) {
private var current: String = axiom
private val td: TurtleDrawing = new TurtleDrawing(xSize, ySize)
def step() {
for (x <- 1 until iterations) {
current = applyRules(current, rules)
}
}
def draw(): VertexArray = {
for (c <- current) {
c match {
case 'F' | 'G' => td.forward(distance)
case '+' => td.anglePlus(angle)
case '-' => td.angleMinus(angle)
case '[' => td.pushStack()
case ']' => td.popStack()
case 'X' | 'Y' => { }
case _ => throw new IllegalArgumentException("Not a valid character: " + c)
}
}
td.vertices
}
private def applyRules(state: String, rules: PartialFunction[Char, String]): String =
current.map {
c => if(rules.isDefinedAt(c)) rules(c)
else c
}.mkString
}
package at.wambo.lsystem
import org.jsfml.graphics._
import org.jsfml.window.{Keyboard, Mouse, VideoMode}
import org.jsfml.window.event.Event
import org.jsfml.system.{Vector2f, Vector2i}
/**
* User: Martin
* Date: 29.05.13
* Time: 15:17
*/
object Main {
var mouseDrag: Boolean = false
var oldMousePos: Vector2i = new Vector2i(0, 0)
val xSize = 1280
val ySize = 800
def handleEvents(window: RenderWindow, event: Event, view: View) {
event.`type` match {
case Event.Type.CLOSED => window.close()
case Event.Type.MOUSE_BUTTON_PRESSED => mouseDrag = true
case Event.Type.MOUSE_BUTTON_RELEASED => mouseDrag = false
case Event.Type.MOUSE_MOVED if mouseDrag => {
val pos = Mouse.getPosition(window)
val delta = new Vector2f(oldMousePos.x - pos.x, oldMousePos.y - pos.y)
view.move(delta)
oldMousePos = pos
}
case Event.Type.KEY_PRESSED => {
event.asKeyEvent().key match {
case Keyboard.Key.W => view.move(0, -4)
case Keyboard.Key.S => view.move(0, 4)
case Keyboard.Key.A => view.move(-4, 0)
case Keyboard.Key.D => view.move(4, 0)
case _ => {}
}
}
case _ => {}
}
}
def main(args: Array[String]) {
val window = new RenderWindow(new VideoMode(xSize, ySize), "L-System")
val defaultView = window.getView
val view = new View(defaultView.getCenter, defaultView.getSize)
view.setCenter(xSize / 2.0f, ySize / 2.0f)
val koch = new LSystem("F", 5, Math.PI / 2.0, 10, 800, 600)({
c: Char => c match {
case 'F' => "F+F-F-F+F"
}
})
koch.step()
val vertices = koch.draw()
while (window.isOpen) {
val e = window.pollEvent()
if (e != null) {
handleEvents(window, e, view)
}
window.clear()
window.draw(vertices)
window.display()
window.setView(view)
}
}
}
package at.wambo.lsystem
import org.jsfml.graphics._
import org.jsfml.system.Vector2f
import java.util
/**
* User: Martin
* Date: 27.05.13
* Time: 16:50
*/
class TurtleDrawing(xSize: Int,
ySize: Int) {
val vertices: VertexArray = new VertexArray(PrimitiveType.LINES)
var color: Color = Color.WHITE
private val stack: util.Stack[Double] = new util.Stack[Double]
private var position: Vector2f = new Vector2f(0, 0)
private var angle: Double = 0
/**
* Moves the turtle forward.
* @param distance distance in pixels to move forward
*/
def forward(distance: Float) {
vertices.add(new Vertex(position, color))
val newPos = new Vector2f((position.x + Math.cos(angle) * distance).asInstanceOf[Float],
(position.y + Math.sin(angle) * distance).asInstanceOf[Float])
position = newPos
vertices.add(new Vertex(newPos, color))
}
/**
* Increases the angle by a given amount.
* @param d Amount to increase the angle with, in radians.
*/
def anglePlus(d: Double) {
angle += d
}
/**
* Decreases the angle by a given amount.
* @param d Amount to decrease the angle with, in radians.
*/
def angleMinus(d: Double) {
angle -= d
}
/**
* Moves the turtle to a given direction,
* without drawing anything.
* @param x X coordinate for new position
* @param y Y coordinate for new position
*/
def moveTo(x: Float, y: Float) {
position = new Vector2f(x, y)
}
/**
* Pushes the current position and angle to the stack
*/
def pushStack() {
stack push position.x
stack push position.y
stack push angle
}
/**
* Gets the position and angle from the stack and
* restores it.
*/
def popStack() {
val y = stack.pop.asInstanceOf[Float]
val x = stack.pop.asInstanceOf[Float]
val ang = stack.pop
moveTo(x, y)
angle = ang
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment