Minor cleanup.
[lsystem3d.git] / src / lindenmayersystem.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 <string>
25
26 #include "lindenmayersystem.h"
27 #include "model.h"
28 #include "rule.h"
29 #include "ruleset.h"
30 #include "turtle.h"
31
32 using namespace std;
33
34
35
36 /**
37 * Constructor
38 * @param model empty model
39 */
40 LindenmayerSystem::LindenmayerSystem(Model *model)
41 {
42 _model = model;
43 _turtle = new Turtle(model);
44
45 clear();
46 }
47
48
49
50 /**
51 * Destructor
52 */
53 LindenmayerSystem::~LindenmayerSystem()
54 {
55 delete _turtle;
56 }
57
58
59
60 /**
61 * Clear all parameters
62 */
63 void LindenmayerSystem::clear()
64 {
65 _axiom.clear();
66 _rules.clear();
67 _turtle->setAngle(0.0);
68 _depth = 0;
69
70 _turtle->reset();
71 _model->clear();
72 }
73
74
75
76 /**
77 * Generate L-system data
78 */
79 void LindenmayerSystem::generate()
80 {
81 // model session
82 _model->begin();
83 _model->setColorIndex(0);
84 recursiveWalk(_axiom.getPreprocessedContent(), _depth);
85 _model->end();
86 }
87
88
89
90 /**
91 * Render L-system data
92 */
93 void LindenmayerSystem::render()
94 {
95 _model->draw();
96 }
97
98
99
100 /**
101 * Set the initial rule (the axiom)
102 * @param axiom the axiom
103 */
104 void LindenmayerSystem::setAxiom(Rule axiom)
105 {
106 _axiom = axiom;
107 }
108
109
110
111 /**
112 * Set one rule
113 * @param rule the rule
114 */
115 void LindenmayerSystem::setRule(Rule rule)
116 {
117 _rules.addRule(rule);
118 }
119
120
121
122 /**
123 * Set the turn/pitch/roll angle
124 * @param degrees the angle, in degrees
125 */
126 void LindenmayerSystem::setAngle(double degrees)
127 {
128 // convert from degrees to radians
129 double radians = (degrees / 360.0) * (2.0 * M_PIl);
130
131 _turtle->setAngle(radians);
132 }
133
134
135
136 /**
137 * Set recursion depth
138 * @param depth depth of recursion
139 */
140 void LindenmayerSystem::setDepth(int depth)
141 {
142 _depth = depth;
143 }
144
145
146
147 /**
148 * Set initial segment diameter
149 * @param diameter the diameter
150 */
151 void LindenmayerSystem::setDiameter(double diameter)
152 {
153 _segmentDiameter = diameter;
154 _model->setDiameter(diameter);
155 }
156
157
158
159 /**
160 * Set segment diameter factor
161 * @param diameterFactor the diameter factor
162 */
163 void LindenmayerSystem::setDiameterFactor(double diameterFactor)
164 {
165 _model->setDiameterFactor(diameterFactor);
166 }
167
168
169
170 /**
171 * Get the initial rule (the axiom)
172 * @return the axiom
173 */
174 Rule LindenmayerSystem::getAxiom()
175 {
176 return _axiom;
177 }
178
179
180
181 /**
182 * Get all rules
183 * @return the rules
184 */
185 RuleSet LindenmayerSystem::getRules()
186 {
187 return _rules;
188 }
189
190
191
192 /**
193 * Get the turn/pitch/roll angle
194 * @return the angle, in degrees
195 */
196 double LindenmayerSystem::getAngle()
197 {
198 double radians = _turtle->getAngle();
199
200 // convert from radians to degrees
201 double degrees = 360.0 * (radians / (2.0 * M_PIl));
202
203 return degrees;
204 }
205
206
207
208 /**
209 * Get recursion depth
210 * @return depth of recursion
211 */
212 int LindenmayerSystem::getDepth()
213 {
214 return _depth;
215 }
216
217
218
219 /**
220 * Get initial segment diameter
221 * @return the diameter
222 */
223 double LindenmayerSystem::getDiameter()
224 {
225 return _segmentDiameter;
226 }
227
228
229
230 /**
231 * Get segment diameter factor
232 * @return the diameter factor
233 */
234 double LindenmayerSystem::getDiameterFactor()
235 {
236 return _model->getDiameterFactor();
237 }
238
239
240
241 /**
242 * Recursively apply the replacement rules
243 * @param rule the rule
244 * @param level recursion level
245 */
246 void LindenmayerSystem::recursiveWalk(string rule, int level)
247 {
248 // process every element in the rule string
249 for (int i = 0; i < rule.size(); i++)
250 {
251 switch (rule[i])
252 {
253 // rule
254 case '@':
255
256 // ignore marker, i.e. the "@"
257 i++;
258
259 // recursion
260 if (level > 0)
261 {
262 string name = rule.substr(i, 1);
263 recursiveWalk(_rules.findRule(name).getPreprocessedContent(), level - 1);
264 }
265
266 break;
267
268
269 // walk / rule
270 case 'F':
271
272 {
273 // replacement rule for 'F'?
274 Rule rule = _rules.findRule("F");
275 if (rule.getProbability() != 0.0 && level > 0)
276 {
277 recursiveWalk(rule.getPreprocessedContent(), level - 1);
278 }
279 else
280 {
281 // no rule for "F"
282 _turtle->walk();
283 }
284 }
285
286 break;
287
288
289 // turn left
290 case '+':
291
292 _turtle->turnLeft();
293 break;
294
295
296 // turn right
297 case '-':
298
299 _turtle->turnRight();
300 break;
301
302
303 // pitch down
304 case '&':
305
306 _turtle->pitchDown();
307 break;
308
309
310 // pitch up
311 case '^':
312
313 _turtle->pitchUp();
314 break;
315
316
317 // roll left
318 case '\\':
319
320 _turtle->rollLeft();
321 break;
322
323
324 // roll right
325 case '/':
326
327 _turtle->rollRight();
328 break;
329
330
331 // turn around 180 degrees
332 case '|':
333
334 _turtle->turnAround();
335 break;
336
337
338 // save state to stack
339 case '[':
340
341 _turtle->push();
342 break;
343
344
345 // load state from stack
346 case ']':
347
348 _turtle->pop();
349 break;
350
351
352 // create a filled surface
353 case '{':
354
355 _model->fillBegin();
356 break;
357
358
359 // close a filled surface
360 case '}':
361
362 _model->fillEnd();
363 break;
364
365
366 // one vertex in a filled surface
367 case 'f':
368
369 _turtle->fillWalk();
370 break;
371
372
373 // decrement segment diameter
374 case '!':
375
376 _model->decrementDiameter();
377 break;
378
379
380 // increment current index to color table
381 case '\'':
382
383 _model->nextColor();
384 break;
385
386
387 // decrement current index to color table
388 case ',':
389
390 _model->prevColor();
391 break;
392 }
393 }
394 }