--- /dev/null
+// Copyright (C) 2006 Erik Dahlberg
+//
+// This file is part of LSystem3d.
+//
+// LSystem3D is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// LSystem3D is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with LSystem3D; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+
+
+#include <cmath>
+
+#include <stack>
+
+#include "coordinate.h"
+#include "model.h"
+#include "turtle.h"
+#include "vector.h"
+
+
+
+/**
+ * Constructor
+ * @param model render this model
+ */
+Turtle::Turtle(Model *model)
+{
+ // initial position and orientation
+ reset();
+
+ // 90 degrees
+ _angle = M_PIl / 2.0;
+
+ _model = model;
+}
+
+
+
+/**
+ * Destructor
+ */
+Turtle::~Turtle()
+{
+}
+
+
+
+/**
+ * Turn left
+ */
+void Turtle::turnLeft()
+{
+ // rotate around "up vector"
+ _heading.rotate(-_angle, _up);
+ _left.rotate(-_angle, _up);
+}
+
+
+
+/**
+ * Turn right
+ */
+void Turtle::turnRight()
+{
+ // rotate around "up vector"
+ _heading.rotate(_angle, _up);
+ _left.rotate(_angle, _up);
+}
+
+
+
+/**
+ * Pitch down
+ */
+void Turtle::pitchDown()
+{
+ // rotate around "left vector"
+ _heading.rotate(-_angle, _left);
+ _up.rotate(-_angle, _left);
+}
+
+
+
+/**
+ * Pitch up
+ */
+void Turtle::pitchUp()
+{
+ // rotate around "left vector"
+ _heading.rotate(_angle, _left);
+ _up.rotate(_angle, _left);
+}
+
+
+
+/**
+ * Roll left
+ */
+void Turtle::rollLeft()
+{
+ // rotate around "heading vector"
+ _left.rotate(_angle, _heading);
+ _up.rotate(_angle, _heading);
+}
+
+
+
+/**
+ * Roll right
+ */
+void Turtle::rollRight()
+{
+ // rotate around "heading vector"
+ _left.rotate(-_angle, _heading);
+ _up.rotate(-_angle, _heading);
+}
+
+
+
+/**
+ * Turn around
+ */
+void Turtle::turnAround()
+{
+ // rotate 180 degrees around "up vector"
+ _heading.rotate(M_PIl, _up);
+ _left.rotate(M_PIl, _up);
+}
+
+
+
+/**
+ * Walk forward
+ */
+void Turtle::walk()
+{
+ // start point
+ double startX = _position.getX();
+ double startY = _position.getY();
+ double startZ = _position.getZ();
+
+ // end point
+ double endX = startX + _heading.getX();
+ double endY = startY + _heading.getY();
+ double endZ = startZ + _heading.getZ();
+
+
+ // move turtle to new position
+ _position.setXYZ(endX, endY, endZ);
+
+ if (!_fenceMode)
+ {
+ // connect the points
+ _model->segment(_diameter,
+ startX, startY, startZ,
+ endX, endY, endZ);
+ }
+ else
+ {
+ // part of a filled surface
+ _model->point(endX, endY, endZ);
+ }
+}
+
+
+
+/**
+ * Save current state to stack
+ */
+void Turtle::push()
+{
+ // position
+ _positionStack.push(_position);
+
+ // orientation
+ _headingStack.push(_heading);
+ _leftStack.push(_left);
+ _upStack.push(_up);
+
+ // diameter
+ _diameterStack.push(_diameter);
+}
+
+
+
+/**
+ * Restore old state from stack
+ */
+void Turtle::pop()
+{
+ // position
+ _position = _positionStack.top(); _positionStack.pop();
+
+ // orientation
+ _heading = _headingStack.top(); _headingStack.pop();
+ _left = _leftStack.top(); _leftStack.pop();
+ _up = _upStack.top(); _upStack.pop();
+
+ // diameter
+ _diameter = _diameterStack.top(); _diameterStack.pop();
+}
+
+
+
+/**
+ * Reset to default state
+ */
+void Turtle::reset()
+{
+ _diameter = 0.1;
+
+ _fenceMode = false;
+
+
+ // put turtle at (0,0,0), head upwards, back towards camera
+
+ _position.setXYZ(0.0, 0.0, 0.0);
+
+ _heading.setXYZ(0.0, 1.0, 0.0);
+ _left.setXYZ(1.0, 0.0, 0.0);
+ _up.setXYZ(0.0, 0.0, 1.0);
+}
+
+
+
+/**
+ * Decrement diameter of segment
+ */
+void Turtle::decrementDiameter()
+{
+ // TODO: dynamic value...
+ _diameter *= 0.8;
+}
+
+
+
+/**
+ * Begin creation of a filled surface
+ */
+void Turtle::fenceInBegin()
+{
+ _fenceMode = true;
+
+ _model->fillBegin();
+ _model->point(_position.getX(), _position.getY(), _position.getZ());
+}
+
+
+
+/**
+ * End creation of a filled surface
+ */
+void Turtle::fenceInEnd()
+{
+ _model->fillEnd();
+
+ _fenceMode = false;
+}
+
+
+
+/**
+ * Set turn/pitch/roll angle
+ * @param angle the angle, in radians
+ */
+void Turtle::setAngle(double radians)
+{
+ _angle = radians;
+}
+
+
+
+/**
+ * Get turn/pitch/roll angle
+ * @return the angle, in radians
+ */
+double Turtle::getAngle()
+{
+ return _angle;
+}