X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=src%2Flindenmayersystem.cpp;h=18339122df83c5e9b8938c7f8bdd73d5568e21ce;hb=HEAD;hp=9a660233f29d9043f846c80a00b5ae83e78165a3;hpb=dd73b028a74ef8b57569c3e76751481d2124e491;p=lsystem3d.git diff --git a/src/lindenmayersystem.cpp b/src/lindenmayersystem.cpp index 9a66023..1833912 100644 --- a/src/lindenmayersystem.cpp +++ b/src/lindenmayersystem.cpp @@ -1,6 +1,6 @@ // Copyright (C) 2006 Erik Dahlberg // -// This file is part of LSystem3d. +// 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 @@ -21,12 +21,12 @@ #include -#include -#include #include #include "lindenmayersystem.h" #include "model.h" +#include "rule.h" +#include "ruleset.h" #include "turtle.h" using namespace std; @@ -35,16 +35,14 @@ using namespace std; /** * Constructor - * @param model the model for generation + * @param model empty model */ LindenmayerSystem::LindenmayerSystem(Model *model) { _model = model; _turtle = new Turtle(model); - _axiom.clear(); - _rules.clear(); - _numIterations = 0; + clear(); } @@ -59,25 +57,64 @@ LindenmayerSystem::~LindenmayerSystem() +/** + * Clear all parameters + */ +void LindenmayerSystem::clear() +{ + _axiom.clear(); + _rules.clear(); + _turtle->setAngle(0.0); + _depth = 0; + + _turtle->reset(); + _model->clear(); +} + + + +/** + * Generate L-system data + */ +void LindenmayerSystem::generate() +{ + // model session + _model->begin(); + _model->setColorIndex(0); + recursiveWalk(_axiom.getPreprocessedContent(), _depth); + _model->end(); +} + + + +/** + * Render L-system data + */ +void LindenmayerSystem::render() +{ + _model->draw(); +} + + + /** * Set the initial rule (the axiom) * @param axiom the axiom */ -void LindenmayerSystem::setAxiom(string axiom) +void LindenmayerSystem::setAxiom(Rule axiom) { - _axiom = verifyAndPreprocessRule(axiom); + _axiom = axiom; } /** * Set one rule - * @param name rule name * @param rule the rule */ -void LindenmayerSystem::setRule(string name, string rule) +void LindenmayerSystem::setRule(Rule rule) { - _rules[name] = verifyAndPreprocessRule(rule); + _rules.addRule(rule); } @@ -97,12 +134,35 @@ void LindenmayerSystem::setAngle(double degrees) /** - * Set the number of iterations - * @param numIterations number of iterations + * Set recursion depth + * @param depth depth of recursion */ -void LindenmayerSystem::setNumIterations(int numIterations) +void LindenmayerSystem::setDepth(int depth) { - _numIterations = numIterations; + _depth = depth; +} + + + +/** + * Set initial segment diameter + * @param diameter the diameter + */ +void LindenmayerSystem::setDiameter(double diameter) +{ + _segmentDiameter = diameter; + _model->setDiameter(diameter); +} + + + +/** + * Set segment diameter factor + * @param diameterFactor the diameter factor + */ +void LindenmayerSystem::setDiameterFactor(double diameterFactor) +{ + _model->setDiameterFactor(diameterFactor); } @@ -111,9 +171,9 @@ void LindenmayerSystem::setNumIterations(int numIterations) * Get the initial rule (the axiom) * @return the axiom */ -string LindenmayerSystem::getAxiom() +Rule LindenmayerSystem::getAxiom() { - return unpreprocessRule(_axiom); + return _axiom; } @@ -122,18 +182,9 @@ string LindenmayerSystem::getAxiom() * Get all rules * @return the rules */ -map LindenmayerSystem::getRules() +RuleSet 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; + return _rules; } @@ -155,66 +206,86 @@ double LindenmayerSystem::getAngle() /** - * Get the number of iterations - * @return number of iterations + * Get recursion depth + * @return depth of recursion */ -int LindenmayerSystem::getNumIterations() +int LindenmayerSystem::getDepth() { - return _numIterations; + return _depth; } /** - * Generate l-system data + * Get initial segment diameter + * @return the diameter */ -void LindenmayerSystem::generate() +double LindenmayerSystem::getDiameter() { - _model->clear(); - - recursiveWalk(_axiom, _numIterations); - - _turtle->reset(); + return _segmentDiameter; } /** - * Walk through the rule string for specified number of levels + * Get segment diameter factor + * @return the diameter factor + */ +double LindenmayerSystem::getDiameterFactor() +{ + return _model->getDiameterFactor(); +} + + + +/** + * Recursively apply the replacement rules * @param rule the rule - * @param level current iteration level + * @param level recursion level */ void LindenmayerSystem::recursiveWalk(string rule, int level) { - // Process every element in the rule string + // process every element in the rule string for (int i = 0; i < rule.size(); i++) { switch (rule[i]) { - // walk + // rule case '@': - + // ignore marker, i.e. the "@" i++; // recursion - if (level == 0) + 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); + string name = rule.substr(i, 1); + recursiveWalk(_rules.findRule(name).getPreprocessedContent(), level - 1); } break; + // walk / rule + case 'F': + + { + // replacement rule for 'F'? + Rule rule = _rules.findRule("F"); + if (rule.getProbability() != 0.0 && level > 0) + { + recursiveWalk(rule.getPreprocessedContent(), level - 1); + } + else + { + // no rule for "F" + _turtle->walk(); + } + } + + break; + + // turn left case '+': @@ -271,100 +342,53 @@ void LindenmayerSystem::recursiveWalk(string rule, int level) break; - // restore state from stack + // load state from stack case ']': _turtle->pop(); break; - // first vertex in a filled surface + // create a filled surface case '{': - _turtle->fenceInBegin(); + _model->fillBegin(); break; - // last vertex in a filled surface + // close a filled surface case '}': - _turtle->fenceInEnd(); + _model->fillEnd(); break; // one vertex in a filled surface case 'f': - _turtle->walk(); + _turtle->fillWalk(); break; - // decrement diameter of segment + // decrement segment diameter case '!': - _turtle->decrementDiameter(); + _model->decrementDiameter(); break; - // unknown operation - default : + // increment current index to color table + case '\'': - // TODO: filter these out when preprocessing - cerr << "Unknown operator in rule string:" << rule[i] << endl; + _model->nextColor(); + break; + + + // decrement current index to color table + case ',': + + _model->prevColor(); 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; -}