*** empty log message ***
[lsystem3d.git] / src / turtle.cpp
1 // Copyright (C) 2006 Erik Dahlberg
2 //
3 // This file is part of LSystem3D.
4 //
5 // LSystem3D is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9 //
10 // LSystem3D is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with LSystem3D; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19
20
21
22 #include <cmath>
23
24 #include <stack>
25
26 #include "coordinate.h"
27 #include "model.h"
28 #include "turtle.h"
29 #include "vector.h"
30
31 using namespace std;
32
33
34
35 /**
36 * Constructor
37 * @param model create this model
38 */
39 Turtle::Turtle(Model *model)
40 {
41 _model = model;
42
43 // initial position and orientation
44 reset();
45
46 // 90 degrees
47 _angle = M_PIl / 2.0;
48 }
49
50
51
52 /**
53 * Destructor
54 */
55 Turtle::~Turtle()
56 {
57 }
58
59
60
61 /**
62 * Turn left
63 */
64 void Turtle::turnLeft()
65 {
66 // rotate around "up vector"
67 _heading.rotate(-_angle, _up);
68 _left.rotate(-_angle, _up);
69 }
70
71
72
73 /**
74 * Turn right
75 */
76 void Turtle::turnRight()
77 {
78 // rotate around "up vector"
79 _heading.rotate(_angle, _up);
80 _left.rotate(_angle, _up);
81 }
82
83
84
85 /**
86 * Pitch down
87 */
88 void Turtle::pitchDown()
89 {
90 // rotate around "left vector"
91 _heading.rotate(-_angle, _left);
92 _up.rotate(-_angle, _left);
93 }
94
95
96
97 /**
98 * Pitch up
99 */
100 void Turtle::pitchUp()
101 {
102 // rotate around "left vector"
103 _heading.rotate(_angle, _left);
104 _up.rotate(_angle, _left);
105 }
106
107
108
109 /**
110 * Roll left
111 */
112 void Turtle::rollLeft()
113 {
114 // rotate around "heading vector"
115 _left.rotate(_angle, _heading);
116 _up.rotate(_angle, _heading);
117 }
118
119
120
121 /**
122 * Roll right
123 */
124 void Turtle::rollRight()
125 {
126 // rotate around "heading vector"
127 _left.rotate(-_angle, _heading);
128 _up.rotate(-_angle, _heading);
129 }
130
131
132
133 /**
134 * Turn around
135 */
136 void Turtle::turnAround()
137 {
138 // rotate 180 degrees around "up vector"
139 _heading.rotate(M_PIl, _up);
140 _left.rotate(M_PIl, _up);
141 }
142
143
144
145 /**
146 * Walk forward
147 */
148 void Turtle::walk()
149 {
150 // start point
151 double startX = _position.getX();
152 double startY = _position.getY();
153 double startZ = _position.getZ();
154
155 // end point
156 double endX = startX + _heading.getX();
157 double endY = startY + _heading.getY();
158 double endZ = startZ + _heading.getZ();
159
160
161 // move turtle to new position
162 _position.setXYZ(endX, endY, endZ);
163
164 // connect start and end point
165 _model->segment(startX, startY, startZ,
166 endX, endY, endZ);
167 }
168
169
170
171 /**
172 * Walk forward, creating a filled surface
173 * TODO: merge with walk() ?
174 */
175 void Turtle::fillWalk()
176 {
177 // end point
178 double destinationX = _position.getX() + _heading.getX();
179 double destinationY = _position.getY() + _heading.getY();
180 double destinationZ = _position.getZ() + _heading.getZ();
181
182 _model->normal(_up.getX(), _up.getY(), _up.getZ());
183
184 // move turtle to new position
185 _position.setXYZ(destinationX, destinationY, destinationZ);
186
187 // part of a filled polygon
188 _model->vertex(destinationX, destinationY, destinationZ);
189 }
190
191
192
193 /**
194 * Save current state to stack
195 */
196 void Turtle::push()
197 {
198 // position
199 _positionStack.push(_position);
200
201 // orientation
202 _headingStack.push(_heading);
203 _leftStack.push(_left);
204 _upStack.push(_up);
205
206 // diameter
207 double diameter = _model->getDiameter();
208 _diameterStack.push(diameter);
209
210 // color index
211 int colorIndex = _model->getColorIndex();
212 _colorIndexStack.push(colorIndex);
213 }
214
215
216
217 /**
218 * Restore old state from stack
219 */
220 void Turtle::pop()
221 {
222 // position
223 _position = _positionStack.top(); _positionStack.pop();
224
225 // orientation
226 _heading = _headingStack.top(); _headingStack.pop();
227 _left = _leftStack.top(); _leftStack.pop();
228 _up = _upStack.top(); _upStack.pop();
229
230 // diameter
231 double diameter = _diameterStack.top(); _diameterStack.pop();
232 _model->setDiameter(diameter);
233
234 // color index
235 int colorIndex = _colorIndexStack.top(); _colorIndexStack.pop();
236 _model->setColorIndex(colorIndex);
237 }
238
239
240
241 /**
242 * Reset to default state
243 */
244 void Turtle::reset()
245 {
246 // put turtle at (0,0,0), head upwards, back towards camera
247
248 _position.setXYZ(0.0, 0.0, 0.0);
249
250 _heading.setXYZ(0.0, 1.0, 0.0);
251 _left.setXYZ(1.0, 0.0, 0.0);
252 _up.setXYZ(0.0, 0.0, 1.0);
253
254
255 // empty the stacks
256 _positionStack = stack<Coordinate>();
257 _headingStack = stack<Vector>();
258 _leftStack = stack<Vector>();
259 _upStack = stack<Vector>();
260 _diameterStack = stack<double>();
261 _colorIndexStack = stack<int>();
262 }
263
264
265
266 /**
267 * Set turn/pitch/roll angle
268 * @param angle the angle, in radians
269 */
270 void Turtle::setAngle(double radians)
271 {
272 _angle = radians;
273 }
274
275
276
277 /**
278 * Get turn/pitch/roll angle
279 * @return the angle, in radians
280 */
281 double Turtle::getAngle()
282 {
283 return _angle;
284 }