Initial revision
[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
32
33 /**
34 * Constructor
35 * @param model render this model
36 */
37 Turtle::Turtle(Model *model)
38 {
39 // initial position and orientation
40 reset();
41
42 // 90 degrees
43 _angle = M_PIl / 2.0;
44
45 _model = model;
46 }
47
48
49
50 /**
51 * Destructor
52 */
53 Turtle::~Turtle()
54 {
55 }
56
57
58
59 /**
60 * Turn left
61 */
62 void Turtle::turnLeft()
63 {
64 // rotate around "up vector"
65 _heading.rotate(-_angle, _up);
66 _left.rotate(-_angle, _up);
67 }
68
69
70
71 /**
72 * Turn right
73 */
74 void Turtle::turnRight()
75 {
76 // rotate around "up vector"
77 _heading.rotate(_angle, _up);
78 _left.rotate(_angle, _up);
79 }
80
81
82
83 /**
84 * Pitch down
85 */
86 void Turtle::pitchDown()
87 {
88 // rotate around "left vector"
89 _heading.rotate(-_angle, _left);
90 _up.rotate(-_angle, _left);
91 }
92
93
94
95 /**
96 * Pitch up
97 */
98 void Turtle::pitchUp()
99 {
100 // rotate around "left vector"
101 _heading.rotate(_angle, _left);
102 _up.rotate(_angle, _left);
103 }
104
105
106
107 /**
108 * Roll left
109 */
110 void Turtle::rollLeft()
111 {
112 // rotate around "heading vector"
113 _left.rotate(_angle, _heading);
114 _up.rotate(_angle, _heading);
115 }
116
117
118
119 /**
120 * Roll right
121 */
122 void Turtle::rollRight()
123 {
124 // rotate around "heading vector"
125 _left.rotate(-_angle, _heading);
126 _up.rotate(-_angle, _heading);
127 }
128
129
130
131 /**
132 * Turn around
133 */
134 void Turtle::turnAround()
135 {
136 // rotate 180 degrees around "up vector"
137 _heading.rotate(M_PIl, _up);
138 _left.rotate(M_PIl, _up);
139 }
140
141
142
143 /**
144 * Walk forward
145 */
146 void Turtle::walk()
147 {
148 // start point
149 double startX = _position.getX();
150 double startY = _position.getY();
151 double startZ = _position.getZ();
152
153 // end point
154 double endX = startX + _heading.getX();
155 double endY = startY + _heading.getY();
156 double endZ = startZ + _heading.getZ();
157
158
159 // move turtle to new position
160 _position.setXYZ(endX, endY, endZ);
161
162 if (!_fenceMode)
163 {
164 // connect the points
165 _model->segment(_diameter,
166 startX, startY, startZ,
167 endX, endY, endZ);
168 }
169 else
170 {
171 // part of a filled surface
172 _model->point(endX, endY, endZ);
173 }
174 }
175
176
177
178 /**
179 * Save current state to stack
180 */
181 void Turtle::push()
182 {
183 // position
184 _positionStack.push(_position);
185
186 // orientation
187 _headingStack.push(_heading);
188 _leftStack.push(_left);
189 _upStack.push(_up);
190
191 // diameter
192 _diameterStack.push(_diameter);
193 }
194
195
196
197 /**
198 * Restore old state from stack
199 */
200 void Turtle::pop()
201 {
202 // position
203 _position = _positionStack.top(); _positionStack.pop();
204
205 // orientation
206 _heading = _headingStack.top(); _headingStack.pop();
207 _left = _leftStack.top(); _leftStack.pop();
208 _up = _upStack.top(); _upStack.pop();
209
210 // diameter
211 _diameter = _diameterStack.top(); _diameterStack.pop();
212 }
213
214
215
216 /**
217 * Reset to default state
218 */
219 void Turtle::reset()
220 {
221 _diameter = 0.1;
222
223 _fenceMode = false;
224
225
226 // put turtle at (0,0,0), head upwards, back towards camera
227
228 _position.setXYZ(0.0, 0.0, 0.0);
229
230 _heading.setXYZ(0.0, 1.0, 0.0);
231 _left.setXYZ(1.0, 0.0, 0.0);
232 _up.setXYZ(0.0, 0.0, 1.0);
233 }
234
235
236
237 /**
238 * Decrement diameter of segment
239 */
240 void Turtle::decrementDiameter()
241 {
242 // TODO: dynamic value...
243 _diameter *= 0.8;
244 }
245
246
247
248 /**
249 * Begin creation of a filled surface
250 */
251 void Turtle::fenceInBegin()
252 {
253 _fenceMode = true;
254
255 _model->fillBegin();
256 _model->point(_position.getX(), _position.getY(), _position.getZ());
257 }
258
259
260
261 /**
262 * End creation of a filled surface
263 */
264 void Turtle::fenceInEnd()
265 {
266 _model->fillEnd();
267
268 _fenceMode = false;
269 }
270
271
272
273 /**
274 * Set turn/pitch/roll angle
275 * @param angle the angle, in radians
276 */
277 void Turtle::setAngle(double radians)
278 {
279 _angle = radians;
280 }
281
282
283
284 /**
285 * Get turn/pitch/roll angle
286 * @return the angle, in radians
287 */
288 double Turtle::getAngle()
289 {
290 return _angle;
291 }