Minor cleanup.
[lsystem3d.git] / src / lindenmayersystem.cpp
CommitLineData
15c82487 1// Copyright (C) 2006 Erik Dahlberg
2//
4ed62b5d 3// This file is part of LSystem3D.
15c82487 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
15c82487 24#include <string>
25
26#include "lindenmayersystem.h"
27#include "model.h"
4ed62b5d 28#include "rule.h"
29#include "ruleset.h"
15c82487 30#include "turtle.h"
31
4ed62b5d 32using namespace std;
33
15c82487 34
35
36/**
37 * Constructor
526db675 38 * @param model empty model
15c82487 39 */
40LindenmayerSystem::LindenmayerSystem(Model *model)
41{
42 _model = model;
43 _turtle = new Turtle(model);
44
526db675 45 clear();
15c82487 46}
47
48
49
50/**
51 * Destructor
52 */
53LindenmayerSystem::~LindenmayerSystem()
54{
55 delete _turtle;
56}
57
58
59
526db675 60/**
61 * Clear all parameters
62 */
63void LindenmayerSystem::clear()
64{
65 _axiom.clear();
66 _rules.clear();
67 _turtle->setAngle(0.0);
4ed62b5d 68 _depth = 0;
526db675 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);
4ed62b5d 84 recursiveWalk(_axiom.getPreprocessedContent(), _depth);
526db675 85 _model->end();
86}
87
88
89
acf054bf 90/**
91 * Render L-system data
92 */
93void LindenmayerSystem::render()
94{
95 _model->draw();
96}
97
98
99
15c82487 100/**
101 * Set the initial rule (the axiom)
102 * @param axiom the axiom
103 */
4ed62b5d 104void LindenmayerSystem::setAxiom(Rule axiom)
15c82487 105{
4ed62b5d 106 _axiom = axiom;
15c82487 107}
108
109
110
111/**
112 * Set one rule
15c82487 113 * @param rule the rule
114 */
4ed62b5d 115void LindenmayerSystem::setRule(Rule rule)
15c82487 116{
4ed62b5d 117 _rules.addRule(rule);
15c82487 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/**
acf054bf 137 * Set recursion depth
4ed62b5d 138 * @param depth depth of recursion
15c82487 139 */
4ed62b5d 140void LindenmayerSystem::setDepth(int depth)
15c82487 141{
4ed62b5d 142 _depth = depth;
15c82487 143}
144
145
146
526db675 147/**
acf054bf 148 * Set initial segment diameter
526db675 149 * @param diameter the diameter
150 */
151void LindenmayerSystem::setDiameter(double diameter)
152{
acf054bf 153 _segmentDiameter = diameter;
526db675 154 _model->setDiameter(diameter);
155}
156
157
158
159/**
acf054bf 160 * Set segment diameter factor
526db675 161 * @param diameterFactor the diameter factor
162 */
163void LindenmayerSystem::setDiameterFactor(double diameterFactor)
164{
165 _model->setDiameterFactor(diameterFactor);
166}
167
168
169
15c82487 170/**
171 * Get the initial rule (the axiom)
172 * @return the axiom
173 */
4ed62b5d 174Rule LindenmayerSystem::getAxiom()
15c82487 175{
4ed62b5d 176 return _axiom;
15c82487 177}
178
179
180
181/**
182 * Get all rules
183 * @return the rules
184 */
4ed62b5d 185RuleSet LindenmayerSystem::getRules()
15c82487 186{
4ed62b5d 187 return _rules;
15c82487 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/**
acf054bf 209 * Get recursion depth
4ed62b5d 210 * @return depth of recursion
15c82487 211 */
4ed62b5d 212int LindenmayerSystem::getDepth()
15c82487 213{
4ed62b5d 214 return _depth;
15c82487 215}
216
217
218
219/**
acf054bf 220 * Get initial segment diameter
221 * @return the diameter
15c82487 222 */
acf054bf 223double LindenmayerSystem::getDiameter()
15c82487 224{
acf054bf 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();
15c82487 237}
238
239
240
241/**
526db675 242 * Recursively apply the replacement rules
acf054bf 243 * @param rule the rule
526db675 244 * @param level recursion level
15c82487 245 */
246void LindenmayerSystem::recursiveWalk(string rule, int level)
247{
526db675 248 // process every element in the rule string
15c82487 249 for (int i = 0; i < rule.size(); i++)
250 {
251 switch (rule[i])
252 {
526db675 253 // rule
15c82487 254 case '@':
526db675 255
15c82487 256 // ignore marker, i.e. the "@"
257 i++;
258
259 // recursion
526db675 260 if (level > 0)
15c82487 261 {
4ed62b5d 262 string name = rule.substr(i, 1);
263 recursiveWalk(_rules.findRule(name).getPreprocessedContent(), level - 1);
526db675 264 }
15c82487 265
526db675 266 break;
267
268
269 // walk / rule
270 case 'F':
271
526db675 272 {
4ed62b5d 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
15c82487 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
4ed62b5d 345 // load state from stack
15c82487 346 case ']':
347
348 _turtle->pop();
349 break;
350
351
526db675 352 // create a filled surface
15c82487 353 case '{':
354
526db675 355 _model->fillBegin();
15c82487 356 break;
357
358
526db675 359 // close a filled surface
15c82487 360 case '}':
361
526db675 362 _model->fillEnd();
15c82487 363 break;
364
365
366 // one vertex in a filled surface
367 case 'f':
368
526db675 369 _turtle->fillWalk();
15c82487 370 break;
371
372
acf054bf 373 // decrement segment diameter
15c82487 374 case '!':
375
526db675 376 _model->decrementDiameter();
15c82487 377 break;
378
379
526db675 380 // increment current index to color table
381 case '\'':
15c82487 382
526db675 383 _model->nextColor();
384 break;
385
386
387 // decrement current index to color table
e017b5ae 388 case ',':
526db675 389
390 _model->prevColor();
15c82487 391 break;
392 }
393 }
394}