Minor cleanup.
[lsystem3d.git] / src / lindenmayersystem.cpp
... / ...
CommitLineData
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
32using namespace std;
33
34
35
36/**
37 * Constructor
38 * @param model empty model
39 */
40LindenmayerSystem::LindenmayerSystem(Model *model)
41{
42 _model = model;
43 _turtle = new Turtle(model);
44
45 clear();
46}
47
48
49
50/**
51 * Destructor
52 */
53LindenmayerSystem::~LindenmayerSystem()
54{
55 delete _turtle;
56}
57
58
59
60/**
61 * Clear all parameters
62 */
63void 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 */
79void 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 */
93void LindenmayerSystem::render()
94{
95 _model->draw();
96}
97
98
99
100/**
101 * Set the initial rule (the axiom)
102 * @param axiom the axiom
103 */
104void LindenmayerSystem::setAxiom(Rule axiom)
105{
106 _axiom = axiom;
107}
108
109
110
111/**
112 * Set one rule
113 * @param rule the rule
114 */
115void 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 */
126void 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 */
140void LindenmayerSystem::setDepth(int depth)
141{
142 _depth = depth;
143}
144
145
146
147/**
148 * Set initial segment diameter
149 * @param diameter the diameter
150 */
151void 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 */
163void 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 */
174Rule LindenmayerSystem::getAxiom()
175{
176 return _axiom;
177}
178
179
180
181/**
182 * Get all rules
183 * @return the rules
184 */
185RuleSet 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 */
196double 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 */
212int LindenmayerSystem::getDepth()
213{
214 return _depth;
215}
216
217
218
219/**
220 * Get initial segment diameter
221 * @return the diameter
222 */
223double LindenmayerSystem::getDiameter()
224{
225 return _segmentDiameter;
226}
227
228
229
230/**
231 * Get segment diameter factor
232 * @return the diameter factor
233 */
234double 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 */
246void 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}