Initial revision
[lsystem3d.git] / lsystem3d / src / turtle.cpp
diff --git a/lsystem3d/src/turtle.cpp b/lsystem3d/src/turtle.cpp
new file mode 100644 (file)
index 0000000..9847b5a
--- /dev/null
@@ -0,0 +1,291 @@
+// 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;
+}