* Adaptation to new classes Rule, RuleSet
[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
15c82487 90/**
91 * Set the initial rule (the axiom)
92 * @param axiom the axiom
93 */
4ed62b5d 94void LindenmayerSystem::setAxiom(Rule axiom)
15c82487 95{
4ed62b5d 96 _axiom = axiom;
15c82487 97}
98
99
100
101/**
102 * Set one rule
15c82487 103 * @param rule the rule
104 */
4ed62b5d 105void LindenmayerSystem::setRule(Rule rule)
15c82487 106{
4ed62b5d 107 _rules.addRule(rule);
15c82487 108}
109
110
111
112/**
113 * Set the turn/pitch/roll angle
114 * @param degrees the angle, in degrees
115 */
116void LindenmayerSystem::setAngle(double degrees)
117{
118 // convert from degrees to radians
119 double radians = (degrees / 360.0) * (2.0 * M_PIl);
120
121 _turtle->setAngle(radians);
122}
123
124
125
126/**
4ed62b5d 127 * Set depth of recursion
128 * @param depth depth of recursion
15c82487 129 */
4ed62b5d 130void LindenmayerSystem::setDepth(int depth)
15c82487 131{
4ed62b5d 132 _depth = depth;
15c82487 133}
134
135
136
526db675 137/**
138 * Set diameter of segment
139 * @param diameter the diameter
140 */
141void LindenmayerSystem::setDiameter(double diameter)
142{
143 _model->setDiameter(diameter);
144}
145
146
147
148/**
149 * Set diameter factor
150 * @param diameterFactor the diameter factor
151 */
152void LindenmayerSystem::setDiameterFactor(double diameterFactor)
153{
154 _model->setDiameterFactor(diameterFactor);
155}
156
157
158
15c82487 159/**
160 * Get the initial rule (the axiom)
161 * @return the axiom
162 */
4ed62b5d 163Rule LindenmayerSystem::getAxiom()
15c82487 164{
4ed62b5d 165 return _axiom;
15c82487 166}
167
168
169
170/**
171 * Get all rules
172 * @return the rules
173 */
4ed62b5d 174RuleSet LindenmayerSystem::getRules()
15c82487 175{
4ed62b5d 176 return _rules;
15c82487 177}
178
179
180
181/**
182 * Get the turn/pitch/roll angle
183 * @return the angle, in degrees
184 */
185double LindenmayerSystem::getAngle()
186{
187 double radians = _turtle->getAngle();
188
189 // convert from radians to degrees
190 double degrees = 360.0 * (radians / (2.0 * M_PIl));
191
192 return degrees;
193}
194
195
196
197/**
4ed62b5d 198 * Get depth of recursion
199 * @return depth of recursion
15c82487 200 */
4ed62b5d 201int LindenmayerSystem::getDepth()
15c82487 202{
4ed62b5d 203 return _depth;
15c82487 204}
205
206
207
208/**
526db675 209 * Get the generated model
210 * @return generated model
15c82487 211 */
526db675 212Model *LindenmayerSystem::getModel()
15c82487 213{
526db675 214 return _model;
15c82487 215}
216
217
218
219/**
526db675 220 * Recursively apply the replacement rules
221 * @param rule rule
222 * @param level recursion level
15c82487 223 */
224void LindenmayerSystem::recursiveWalk(string rule, int level)
225{
526db675 226 // process every element in the rule string
15c82487 227 for (int i = 0; i < rule.size(); i++)
228 {
229 switch (rule[i])
230 {
526db675 231 // rule
15c82487 232 case '@':
526db675 233
15c82487 234 // ignore marker, i.e. the "@"
235 i++;
236
237 // recursion
526db675 238 if (level > 0)
15c82487 239 {
4ed62b5d 240 string name = rule.substr(i, 1);
241 recursiveWalk(_rules.findRule(name).getPreprocessedContent(), level - 1);
526db675 242 }
15c82487 243
526db675 244 break;
245
246
247 // walk / rule
248 case 'F':
249
526db675 250 {
4ed62b5d 251 // replacement rule for 'F'?
252 Rule rule = _rules.findRule("F");
253 if (rule.getProbability() != 0.0 && level > 0)
254 {
255 recursiveWalk(rule.getPreprocessedContent(), level - 1);
256 }
257 else
258 {
259 // no rule for "F"
260 _turtle->walk();
261 }
262 }
263
15c82487 264 break;
265
266
267 // turn left
268 case '+':
269
270 _turtle->turnLeft();
271 break;
272
273
274 // turn right
275 case '-':
276
277 _turtle->turnRight();
278 break;
279
280
281 // pitch down
282 case '&':
283
284 _turtle->pitchDown();
285 break;
286
287
288 // pitch up
289 case '^':
290
291 _turtle->pitchUp();
292 break;
293
294
295 // roll left
296 case '\\':
297
298 _turtle->rollLeft();
299 break;
300
301
302 // roll right
303 case '/':
304
305 _turtle->rollRight();
306 break;
307
308
309 // turn around 180 degrees
310 case '|':
311
312 _turtle->turnAround();
313 break;
314
315
316 // save state to stack
317 case '[':
318
319 _turtle->push();
320 break;
321
322
4ed62b5d 323 // load state from stack
15c82487 324 case ']':
325
326 _turtle->pop();
327 break;
328
329
526db675 330 // create a filled surface
15c82487 331 case '{':
332
526db675 333 _model->fillBegin();
15c82487 334 break;
335
336
526db675 337 // close a filled surface
15c82487 338 case '}':
339
526db675 340 _model->fillEnd();
15c82487 341 break;
342
343
344 // one vertex in a filled surface
345 case 'f':
346
526db675 347 _turtle->fillWalk();
15c82487 348 break;
349
350
351 // decrement diameter of segment
352 case '!':
353
526db675 354 _model->decrementDiameter();
15c82487 355 break;
356
357
526db675 358 // increment current index to color table
359 case '\'':
15c82487 360
526db675 361 _model->nextColor();
362 break;
363
364
365 // decrement current index to color table
e017b5ae 366 case ',':
526db675 367
368 _model->prevColor();
15c82487 369 break;
370 }
371 }
372}