X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=lsystem3d%2Fsrc%2Flindenmayersystem.cpp;fp=lsystem3d%2Fsrc%2Flindenmayersystem.cpp;h=9a660233f29d9043f846c80a00b5ae83e78165a3;hb=e5247a3b88c449937af08f46afc271afda2954a2;hp=0000000000000000000000000000000000000000;hpb=c48a55e9e62ed7a9d46e3c6a53faae4bc05856e5;p=lsystem3d.git diff --git a/lsystem3d/src/lindenmayersystem.cpp b/lsystem3d/src/lindenmayersystem.cpp new file mode 100644 index 0000000..9a66023 --- /dev/null +++ b/lsystem3d/src/lindenmayersystem.cpp @@ -0,0 +1,370 @@ +// Copyright (C) 2006 Erik Dahlberg +// +// This file is part of LSystem3d. +// +// LSystem3D is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// LSystem3D is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with LSystem3D; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + + + +#include + +#include +#include +#include + +#include "lindenmayersystem.h" +#include "model.h" +#include "turtle.h" + +using namespace std; + + + +/** + * Constructor + * @param model the model for generation + */ +LindenmayerSystem::LindenmayerSystem(Model *model) +{ + _model = model; + _turtle = new Turtle(model); + + _axiom.clear(); + _rules.clear(); + _numIterations = 0; +} + + + +/** + * Destructor + */ +LindenmayerSystem::~LindenmayerSystem() +{ + delete _turtle; +} + + + +/** + * Set the initial rule (the axiom) + * @param axiom the axiom + */ +void LindenmayerSystem::setAxiom(string axiom) +{ + _axiom = verifyAndPreprocessRule(axiom); +} + + + +/** + * Set one rule + * @param name rule name + * @param rule the rule + */ +void LindenmayerSystem::setRule(string name, string rule) +{ + _rules[name] = verifyAndPreprocessRule(rule); +} + + + +/** + * Set the turn/pitch/roll angle + * @param degrees the angle, in degrees + */ +void LindenmayerSystem::setAngle(double degrees) +{ + // convert from degrees to radians + double radians = (degrees / 360.0) * (2.0 * M_PIl); + + _turtle->setAngle(radians); +} + + + +/** + * Set the number of iterations + * @param numIterations number of iterations + */ +void LindenmayerSystem::setNumIterations(int numIterations) +{ + _numIterations = numIterations; +} + + + +/** + * Get the initial rule (the axiom) + * @return the axiom + */ +string LindenmayerSystem::getAxiom() +{ + return unpreprocessRule(_axiom); +} + + + +/** + * Get all rules + * @return the rules + */ +map LindenmayerSystem::getRules() +{ + map theUnpreprocessedRules; + + // unpreprocess all rules + map::iterator currentRule; + for (currentRule = _rules.begin(); currentRule != _rules.end(); currentRule++) + { + theUnpreprocessedRules[currentRule->first] = unpreprocessRule(currentRule->second); + } + + return theUnpreprocessedRules; +} + + + +/** + * Get the turn/pitch/roll angle + * @return the angle, in degrees + */ +double LindenmayerSystem::getAngle() +{ + double radians = _turtle->getAngle(); + + // convert from radians to degrees + double degrees = 360.0 * (radians / (2.0 * M_PIl)); + + return degrees; +} + + + +/** + * Get the number of iterations + * @return number of iterations + */ +int LindenmayerSystem::getNumIterations() +{ + return _numIterations; +} + + + +/** + * Generate l-system data + */ +void LindenmayerSystem::generate() +{ + _model->clear(); + + recursiveWalk(_axiom, _numIterations); + + _turtle->reset(); +} + + + +/** + * Walk through the rule string for specified number of levels + * @param rule the rule + * @param level current iteration level + */ +void LindenmayerSystem::recursiveWalk(string rule, int level) +{ + // Process every element in the rule string + for (int i = 0; i < rule.size(); i++) + { + switch (rule[i]) + { + // walk + case '@': + + // ignore marker, i.e. the "@" + i++; + + // recursion + if (level == 0) + { + // at lowest level, start rendering + + _turtle->walk(); + } + else + { + // more levels to go + + char ruleName[] = {rule[i], '\0'}; + recursiveWalk(_rules[ruleName], level - 1); + } + + break; + + + // turn left + case '+': + + _turtle->turnLeft(); + break; + + + // turn right + case '-': + + _turtle->turnRight(); + break; + + + // pitch down + case '&': + + _turtle->pitchDown(); + break; + + + // pitch up + case '^': + + _turtle->pitchUp(); + break; + + + // roll left + case '\\': + + _turtle->rollLeft(); + break; + + + // roll right + case '/': + + _turtle->rollRight(); + break; + + + // turn around 180 degrees + case '|': + + _turtle->turnAround(); + break; + + + // save state to stack + case '[': + + _turtle->push(); + break; + + + // restore state from stack + case ']': + + _turtle->pop(); + break; + + + // first vertex in a filled surface + case '{': + + _turtle->fenceInBegin(); + break; + + + // last vertex in a filled surface + case '}': + + _turtle->fenceInEnd(); + break; + + + // one vertex in a filled surface + case 'f': + + _turtle->walk(); + break; + + + // decrement diameter of segment + case '!': + + _turtle->decrementDiameter(); + break; + + + // unknown operation + default : + + // TODO: filter these out when preprocessing + cerr << "Unknown operator in rule string:" << rule[i] << endl; + break; + } + } +} + + + +/** + * Verify and preprocess one rule string + * @param ruleOrAxiom the rule + * @return the preprocessed rule + */ +string LindenmayerSystem::verifyAndPreprocessRule(string ruleOrAxiom) +{ + // for now, simply put "@" before every rewriting operator + // TODO: verifying + + string preprocessedRule; + + // check every element in rule + for (int i = 0; i < ruleOrAxiom.size(); i++) + { + // TODO: remove the A-Z limit: use strings, not single chars + if (ruleOrAxiom[i] >= 'A' && ruleOrAxiom[i] <= 'Z') + { + // mark as rewriting operator + preprocessedRule += '@'; + } + preprocessedRule += ruleOrAxiom[i]; + } + + return preprocessedRule; +} + + + +/** + * Unpreprocess one rule string + * @param ruleOrAxiom the rule + * @return the unpreprocessed rule + */ +string LindenmayerSystem::unpreprocessRule(string ruleOrAxiom) +{ + string unpreprocessedRule; + + // check every element in rule + for (int i = 0; i < ruleOrAxiom.size(); i++) + { + // ignore rewriting marker + if (ruleOrAxiom[i] != '@') + { + unpreprocessedRule += ruleOrAxiom[i]; + } + } + + return unpreprocessedRule; +}