Logo Search packages:      
Sourcecode: k3d version File versions

l_parser.cpp

Go to the documentation of this file.
// K-3D
// Copyright (c) 1995-2004, Timothy M. Shead
//
// Contact: tshead@k-3d.com
//
// This program 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.
//
// This program 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 this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

/** \file
            \author Romain Behar (romainbehar@yahoo.com)
*/

#include <k3dsdk/classes.h>
#include <k3dsdk/color.h>
#include <k3dsdk/file_helpers.h>
#include <k3dsdk/imaterial.h>
#include <k3dsdk/material.h>
#include <k3dsdk/material_collection.h>
#include <k3dsdk/measurement.h>
#include <k3dsdk/mesh_source.h>
#include <k3dsdk/module.h>
#include <k3dsdk/object.h>
#include <k3dsdk/path_data.h>
#include <k3dsdk/persistence.h>
#include <k3dsdk/plugins.h>
#include <k3dsdk/property.h>
#include <k3dsdk/string_modifiers.h>
#include <k3dsdk/transform.h>

#include <boost/filesystem/fstream.hpp>
#include <boost/filesystem/path.hpp>

#include <cmath>
#include <fstream>
#include <limits>
#include <map>
#include <sstream>
#include <stack>

namespace libk3dlsystem
{

namespace lparser
{

// Based on free code from Laurens Lapre
// http://home.wanadoo.nl/laurens.lapre/lparser.htm
// for more information, read share/doc/lsystem.txt


// Rules
std::vector<std::string> rules;

// Marked rules need special processing when growing shapes are active
std::vector<bool> marks;

// Used to build the production string
std::string object_string;

// Settings stack used for solving [] references
typedef struct s_rec
{
      k3d::vector3      pos;  // position in 3space of turtle origin
      k3d::vector3      fow;  // forward direction

      k3d::vector3      lef;  // left direction
      k3d::vector3      upp;  // up direction
      k3d::vector3      last; // last position used for connecting cylinders
      k3d::vector3      last_v[8];  // last vertices of object used for connecting cylinders
      double            dis;  // value of F distance
      double            ang;  // value of basic angle
      double            thick;      // value of thickness
      double            dis2; // value of Z distance
      double            tr;   // trope value
      unsigned long     col;  // current color
      unsigned long     last_col;   // color of last object
} s_rec;

// Flags
bool trope_set = false;
bool rand_set = false;
bool closed_form = false;
bool last_recur = false; // processing the last recursion step

// Init vars
double            thick, min_thick = 0.0, rand_amount = 0.0;
double            trope_amount = 0.0;
unsigned long     polcount = 0;
// Limit total generated polygons
unsigned long     poly_limit = 500000L;
// Set maximum production string size in kbytes
unsigned long     max_string = 2L * 1024L * 1024L;
unsigned long     col = 2, lev, last_col = 0;
double            dis, ang, dis2, tr = 0.2;
k3d::vector3      sky(0.0, 0.0, 1.0), trope;
k3d::vector3      last(1.0, 1.0, 1.0), last_v[8];
double            fraction;
k3d::vector3      axis_x, axis_y, axis_z;

// Stacks []
std::stack<s_rec> stack;
s_rec save;

// Polygon stack used for solving {} references
typedef std::vector<k3d::vector3> vectors_t;
std::stack<vectors_t> pstack;

// Max size of the [] and {} stacks during drawing
// useful during mutation
unsigned long     max_stack_size = 1000;

// Polygons
class polygon
{
public:
      unsigned long a;
      unsigned long b;
      unsigned long c;
      unsigned long d;

      polygon()
      {
            a = b = c = d = 0;
      }

      polygon(unsigned long A, unsigned long B, unsigned long C, unsigned long D) :
            a(A), b(B), c(C), d(D)
      {
      }
};


// Store vertices and polygons
vectors_t vertices;
typedef std::vector<polygon> polygons_t;
polygons_t polygons;

// Bounding-box
k3d::bounding_box bounding_box;
double bbox_x = 0;
double bbox_y = 0;
double bbox_z = 0;

// LViewer colors
const unsigned long color_number = 15;
k3d::color colors[color_number] = {
      k3d::color(0.5, 0.5, 0.5), // default
      k3d::color(0.3, 0.3, 0.3),
      k3d::color(0.8, 0.4, 0.4),
      k3d::color(0.8, 0.8, 0.4),
      k3d::color(0.4, 0.8, 0.4),
      k3d::color(0.4, 0.8, 0.8),
      k3d::color(0.4, 0.4, 0.8),
      k3d::color(0.8, 0.4, 0.8),
      k3d::color(0.2, 0.5, 0.2),
      k3d::color(0.2, 0.5, 0.5),
      k3d::color(0.2, 0.2, 0.5),
      k3d::color(0.5, 0.2, 0.5),
      k3d::color(0.6, 0.2, 0.2),
      k3d::color(0.5, 0.5, 0.5),
      k3d::color(0.9, 0.9, 0.9)
};

// Save an object from store to disc
bool add_geometry(unsigned long color, k3d::mesh* mesh)
{
      std::vector<k3d::point*> points;

      for(unsigned long t = 0; t < vertices.size(); t++)
            {
                  // Change handedness
                  double x = - vertices[t][0];
                  double y = vertices[t][2];
                  double z = - vertices[t][1];
                  k3d::point* point = new k3d::point(x, y, z);
                  points.push_back(point);
                  mesh->points.push_back(point);

                  bounding_box.insert(point->position);
            }

      for(unsigned long t = 0; t < polygons.size(); t++)
            {
                  k3d::polyhedron::edges_t edges;
                  edges.push_back(new k3d::split_edge(points[polygons[t].a]));
                  edges.push_back(new k3d::split_edge(points[polygons[t].b]));
                  edges.push_back(new k3d::split_edge(points[polygons[t].c]));

                  if(polygons[t].c != polygons[t].d)
                        edges.push_back(new k3d::split_edge(points[polygons[t].d]));

                  k3d::loop_edges(edges.begin(), edges.end());
                  k3d::polyhedron& polyhedron = *mesh->polyhedra.back();
                  polyhedron.edges.insert(polyhedron.edges.end(), edges.begin(), edges.end());

                  k3d::face* new_face = new k3d::face(edges.front());
                  return_val_if_fail(new_face, false);
                  polyhedron.faces.push_back(new_face);

                  // Set color ...
                  unsigned long color_index = color;
                  if(color_index > color_number - 1)
                        color_index = 0;

                  new_face->uniform_data["Cs"] = colors[color_index];
            }

      return true;
}


// Here we build a cube shape directly on the input vectors
void add_cube(k3d::vector3 start, k3d::vector3 end, k3d::vector3 up, unsigned long color, k3d::mesh* mesh)
{
      // Check size
      k3d::vector3 direction = end - start;
      double length = direction.Length();
      if(length == 0)
            return;

      double s = length * thick;
      s = std::max(s, min_thick);
      s *= 0.5;

      k3d::vector3 d1 = direction;
      d1.Normalize();

      k3d::vector3 d2 = up;
      d2.Normalize();

      k3d::vector3 d3 = d1 ^ d2;
      d3.Normalize();

      vertices.clear();
      vertices.resize(4);

      // Base 1, 3
      d1 = d2 + d3;
      d1.Normalize();
      vertices[0] = start + s * d1;
      vertices[2] = start + (-s) * d1;

      // Base 2, 4
      d1 = d2 - d3;
      d1.Normalize();
      vertices[1] = start + s * d1;
      vertices[3] = start + (-s) * d1;

      // Top
      for(unsigned long i = 0; i < 4; i++)
            vertices.push_back(vertices[i] + direction);

      // Polygons
      polygons.clear();
      polygons.push_back(polygon(0, 4, 5, 1));
      polygons.push_back(polygon(1, 5, 6, 2));
      polygons.push_back(polygon(2, 6, 7, 3));
      polygons.push_back(polygon(3, 7, 4, 0));
      polygons.push_back(polygon(0, 1, 2, 3));
      polygons.push_back(polygon(7, 6, 5, 4));

      add_geometry(color, mesh);
}

// The lastxxx vars are used to store the previous top of the cylinder
// for connecting a next one; since the vars are stacked for [] we can
// connect correctly according to current nesting level
void add_cylinder(k3d::vector3 start, k3d::vector3 end, k3d::vector3 up, unsigned long color, k3d::mesh* mesh)
{
      // Check size
      k3d::vector3 direction = end - start;
      double length = direction.Length();
      if(length == 0.0)
            return;

      double s = length * thick;
      s = std::max(s, min_thick);
      s *= 0.5;

      k3d::vector3 d1 = direction;
      d1.Normalize();

      k3d::vector3 d2 = up;
      d2.Normalize();

      k3d::vector3 d3 = d1 ^ d2;
      d3.Normalize();

      k3d::vector3 t1 = d2 + d3;
      t1.Normalize();
      k3d::vector3 t2 = d2 - d3;
      t2.Normalize();

      vertices.clear();
      vertices.resize(8);

      vertices[0] = start + s * t1;
      vertices[4] = start + (-s) * t1;
      vertices[2] = start + s * t2;
      vertices[6] = start + (-s) * t2;

      s *= 0.7071;
      vertices[1] = start + s * t1 + s * t2;
      vertices[3] = start + (-s) * t1 + s * t2;
      vertices[5] = start + (-s) * t1 + (-s) * t2;
      vertices[7] = start + s * t1 + (-s) * t2;

      // Top
      for(unsigned long i = 0; i < 8; i++)
            vertices.push_back(vertices[i] + direction);

      if(last_col == color)
            {
                  direction = start - last;
                  length = direction.Length();
                  double dd = std::numeric_limits<double>::max();

                  // Connect cylinders if near enough
                  if(length < 1.0)
                        {
                              // Find nearest vertex
                              unsigned long ii = 0;
                              for(unsigned long i = 0; i < 8; i++)
                                    {
                                          direction = vertices[0] - last_v[i];
                                          length = direction.Length();
                                          if(length < dd)
                                                {
                                                      dd = length;
                                                      ii = i;
                                                }
                                    }

                              for(unsigned long i = 0; i < 8; i++)
                                    {
                                          vertices[i] = last_v[ii];
                                          ii = (ii + 1) % 8;
                                    }
                        }
            }

      // Polygons
      polygons.clear();
      polygons.push_back(polygon(0, 8, 9, 1));
      polygons.push_back(polygon(1, 9, 10, 2));
      polygons.push_back(polygon(2, 10, 11, 3));
      polygons.push_back(polygon(3, 11, 12, 4));
      polygons.push_back(polygon(4, 12, 13, 5));
      polygons.push_back(polygon(5, 13, 14, 6));
      polygons.push_back(polygon(6, 14, 15, 7));
      polygons.push_back(polygon(7, 15, 8, 0));

      add_geometry(color, mesh);

      // Save cylinder's parameters and top vertices
      last_col = color;
      last = end;
      for(unsigned long i = 0; i < 8; i++)
            last_v[i] = vertices[i + 8];
}

// L-system routines ------------------------------------------------------

// Get a line from a .ls file;
// skips comments (lines beginning with '#') and empty lines
bool ls_line(std::istream& file, std::string& linebuffer)
{
      while(!file.eof())
            {
                  k3d::getline(file, linebuffer);

                  // Skip comments ...
                  if(linebuffer[0] == '#')
                        continue;

                  // Skip blank lines
                  if(!(k3d::trim(linebuffer)).size())
                        continue;

                  // Must qualify
                  return true;
            }

      // end-of-file reached
      return false;
}

bool load_configuration_values(const boost::filesystem::path& file_path, double& recursion, double& basic_angle, double& thickness)
{
      // Open configuration file
      boost::filesystem::ifstream file(file_path);
      if(!file.good())
            {
                  std::cerr << __PRETTY_FUNCTION__ << ": error opening [" << file_path.native_file_string() << "]" << std::endl;
                  return 0.0;
            }

      // Get recursion level
      std::string temp;
      return_val_if_fail(ls_line(file, temp), false);
      std::stringstream scan(temp);
      scan >> recursion;

      // Get asic angle
      return_val_if_fail(ls_line(file, temp), false);
      std::stringstream scan2(temp);
      scan2 >> basic_angle;

      // Get thickness
      return_val_if_fail(ls_line(file, temp), false);
      std::stringstream scan3(temp);
      scan3 >> thickness;

      return true;
}

// Process a ls file and setup rules
bool load_configuration_rules(const double recursion, const double basic_angle, const double thickness, const boost::filesystem::path& file_path)
{
      // Open grammar file
      boost::filesystem::ifstream file(file_path);
      if(!file.good())
            {
                  std::cerr << __PRETTY_FUNCTION__ << ": error opening [" << file_path.native_file_string() << "]" << std::endl;
                  return false;
            }

      // Set default values
      trope_set = false;
      rand_set = false;
      closed_form = false;
      last_recur = false;

      min_thick = 0.0; rand_amount = 0.0;
      trope_amount = 0.0;
      polcount = 0;
      poly_limit = 500000L;
      col = 2; last_col = 0;
      tr = 0.2;
      sky = k3d::vector3(0.0, 0.0, 1.0);
      last = k3d::vector3(1.0, 1.0, 1.0);

      // Clear stacks
      stack = std::stack<s_rec>();
      pstack = std::stack<vectors_t>();

      // Skip but setup recursion level, basic angle and thickness
      std::string temp;
      return_val_if_fail(ls_line(file, temp), false);

      lev = (unsigned long)std::floor(recursion);
      fraction = recursion - (double)lev;
      if(fraction > 0)
            lev++;

      return_val_if_fail(ls_line(file, temp), false);
      ang = basic_angle / 180 * 3.141592654;

      return_val_if_fail(ls_line(file, temp), false);
      thick = thickness / 100;

      // Axiom
      return_val_if_fail(ls_line(file, temp), false);

      object_string = strtok(const_cast<char*>(temp.c_str()), " \r\n\t#");

      // Get rules
      rules.clear();
      for(unsigned long i = 0; i < 150; i++)
            {
                  return_val_if_fail(ls_line(file, temp), false);

                  std::string rule = strtok(const_cast<char*>(temp.c_str()), " \r\n\t#");

                  if(!rule.size())
                        continue;

                  if(rule[0] == '@')
                        break;

                  rules.push_back(rule);
            }

      // Add default rules
      rules.push_back("+=+");
      rules.push_back("-=-");
      rules.push_back("&=&");
      rules.push_back("^=^");
      rules.push_back("<=<");
      rules.push_back(">=>");

      rules.push_back("%=%");
      rules.push_back("|=|");
      rules.push_back("!=!");
      rules.push_back("?=?");
      rules.push_back(":=:");
      rules.push_back(";=;");
      rules.push_back("\'=\'");
      rules.push_back("\"=\"");
      rules.push_back("c=c");

      rules.push_back("[=[");
      rules.push_back("]=]");
      rules.push_back("{={");
      rules.push_back("}=}");

      rules.push_back("F=F");
      rules.push_back("f=f");
      rules.push_back("t=t");
      rules.push_back("g=g");
      rules.push_back("Z=Z");
      rules.push_back("z=z");
      rules.push_back("*=*");
      rules.push_back("$=$");
      rules.push_back("~=~");

      rules.push_back(".=.");
      rules.push_back("1=1");
      rules.push_back("2=2");
      rules.push_back("3=3");
      rules.push_back("4=4");
      rules.push_back("5=5");
      rules.push_back("6=6");
      rules.push_back("7=7");
      rules.push_back("8=8");
      rules.push_back("9=9");
      rules.push_back("0=0");
      rules.push_back("(=(");
      rules.push_back(")=)");

      // Closer default
      rules.push_back("_=_");

      // Set start values for F and Z distances
      dis = 100.0;
      dis2 = dis * 0.5;

      // Get marks
      marks.clear();
      for(unsigned long n = 0; n < rules.size(); n++)
            marks.push_back(false);

      // Check which rules need to be marked for last recursion when growing
      for(unsigned long n = 0; n < rules.size(); n++)
            {
                  if(rules[n][0] == '+')
                        break;

                  marks[n] = true;

                  // All rules with basic move/block before '=' mark false
                  if(rules[n][0] == 'F')
                        marks[n] = false;
                  if(rules[n][0] == 'f')
                        marks[n] = false;
                  if(rules[n][0] == 'Z')
                        marks[n] = false;
                  if(rules[n][0] == 'z')
                        marks[n] = false;
            }

      return true;
}

// Apply mutations to the rules
const double inv_max = 1.0 / RAND_MAX;
double Rnd()
{
      return rand() * inv_max;
}

void L_mutate()
{
      unsigned long n;
      for(n = 0; n < rules.size(); n++)
            if(rules[n][0] == '+')
                  break;

      double rules_n = static_cast<double>(n);
      const unsigned long max = 1000;

      unsigned long i = static_cast<unsigned long>(Rnd() * 6.0);
      switch(i)
            {
                  default:
                        return;

                  // Insert
                  case 1:
                  {
                        std::string T("");
                        i = static_cast<unsigned long>(Rnd() * rules_n);
                        T = rules[i][0];

                        unsigned long j = static_cast<unsigned long>(Rnd() * rules_n);

                        unsigned long k = (unsigned long)(Rnd() * (double)rules[j].length());
                        k = (k < 2) ? 2 : k;
                        std::string rulet = std::string(rules[j], k);
                        rules[j].replace(k, rulet.length(), '[' + T + ']');
                        rules[j].replace(k, rulet.length(), std::string('[' + T + ']'));

                        rules[j] += rulet;
                  }
                  break;

                  // Replace
                  case 0:
                  case 2:
                  {
                        std::string R("");
                        std::string T("");

                        do
                              {
                                    unsigned long i = static_cast<unsigned long>(Rnd() * rules_n);
                                    unsigned long j = static_cast<unsigned long>(Rnd() * rules_n);
                                    T = rules[i][0];
                                    R = rules[j][0];
                              }
                        while(T == R);

                        for(unsigned long ii = 0; ii < max; ii++)
                              {
                                    i = static_cast<unsigned long>(Rnd() * rules_n);
                                    for(unsigned long j = 2; j < (rules[i]).length(); j++)
                                          {
                                                if(rules[i][j] == T[0])
                                                      {
                                                            rules[i][j] = R[0];
                                                            return;
                                                      }
                                          }
                              }
                  }
                  break;

                  // Append
                  case 3:
                  {
                        std::string S("");
                        i = static_cast<unsigned long>(Rnd() * rules_n);
                        S = rules[i][0];

                        i = static_cast<unsigned long>(Rnd() * rules_n);
                        rules[i] = S;
                  }
                  break;

                  // Swap directions
                  case 4:
                        for(unsigned long ii = 0; ii < max; ii++)
                              {
                                    i = static_cast<unsigned long>(Rnd() * rules_n);
                                    for(unsigned long j = 2; j < rules[i].size(); j++)
                                          {
                                                char mutations[12][2] = {
                                                      { '+', '-' },
                                                      { '-', '+' },
                                                      { '&', '^' },
                                                      { '^', '&' },
                                                      { '>', '<' },
                                                      { '<', '>' },
                                                      { '|', '%' },
                                                      { '%', '|' },
                                                      { ':', ';' },
                                                      { ';', ':' },
                                                      { '\'', '"' },
                                                      { '"', '\'' } };

                                                unsigned long random = (unsigned long)(Rnd() * 12.0);

                                                if(random < 0 || random > 11)
                                                      return;

                                                if(rules[i][j] == mutations[random][0])
                                                      {
                                                            rules[i][j] = mutations[random][1];
                                                            return;
                                                      }
                                          }
                              }
                  break;

                  // Swap sizes
                  case 5:
                        for(unsigned long ii = 0; ii < max; ii++)
                              {
                                    i = static_cast<unsigned long>(Rnd() * rules_n);
                                    for(unsigned long j = 2; j < rules[i].size(); j++)
                                          {
                                                char mutations[6][2] = {
                                                      { 'F', 'Z' },
                                                      { 'Z', 'F' },
                                                      { 'f', 'z' },
                                                      { 'z', 'f' },
                                                      { '!', '?' },
                                                      { '?', '!' } };

                                                unsigned long random = (unsigned long)(Rnd() * 6.0);

                                                if(random < 0 || random > 5)
                                                      return;

                                                if(rules[i][j] == mutations[random][0])
                                                      {
                                                            rules[i][j] = mutations[random][1];
                                                            return;
                                                      }
                                          }
                              }
                  break;
            }
}

// Expand l-system into production string.
// object_string is read with the k counter and
// the next generation is built up in otemp
void L_system()
{
      // Map rule names
      typedef std::map<char, unsigned long> map_t;
      map_t S;

      // Each char gets a rule number
      for(unsigned long i = rules.size(); i > 0; i--)
            if(rules[i - 1].size())
                  S[(rules[i - 1][0])] = i - 1;

      // For each recursion
      unsigned long max = max_string - 10L;
      bool incomplete = false;
      for(unsigned long l = 0; l < lev; l++)
            {
                  // Need markers ?
                  bool marker = (l == (lev - 1)) && (fraction != 0.0);

                  std::string otemp("");
                  unsigned long ss = 0;

                  // For each char in the string
                  for(unsigned long k = 0; k < object_string.size(); k++)
                        {
                              // Default rule which does nothing
                              unsigned long i = rules.size() - 1;
                              // i = rule number attached to current char
                              map_t::const_iterator find_rule = S.find(object_string[k]);
                              if(find_rule != S.end())
                                    i = find_rule->second;

                              // s = size of current rule
                              unsigned long s = rules[i].size() - 2;
                              ss += s;

                              // Overflow
                              if(ss >= max)
                                    {
                                          l = lev;
                                          incomplete = true;
                                          break;

                                    }

                              // Add mark char
                              if(marker && marks[i])
                                    {
                                          otemp += '@';
                                          otemp += std::string(rules[i], 2, s);
                                          otemp += '@';
                                    }
                              else
                                    {
                                          // Copy
                                          otemp += std::string(rules[i], 2, s);
                                    }
                        }

                  // Copy the temp string to object_string and repeat cycle
                  object_string = otemp;
            }
}

// Save mutated ls-system for re-run
void L_save()
{
/*
      remove("mutation.ls");
      FILE* f = fopen("mutation.ls", "wt");
      if(!f)
            User_error("Cannot open file [mutation.ls]");

      fprintf(f, "%d\n", lev);
      fprintf(f, "%g\n", (ang / 3.141592654) * 180.0);
      fprintf(f, "%g\n", thick * 100.0);

      fprintf(f, "%s\n", object_string.c_str());

      for(unsigned long i = 0; i < rules.size(); i++)
            {
                  if(rules[i][0] == '+')
                        break;

                  fprintf(f, "%s\n", rules[i].c_str());
            }

      fprintf(f, "@\n");
      fclose(f);
*/
}

// Read a (xx) value from a production string
// at location j and return it as double
double parse_value(unsigned long& j)
{
      // Skip current character and '('
      j += 2;

      std::string val("");
      while(object_string[j] != ')')
            val += object_string[j++];

      std::stringstream scan(val);
      double r = 0.0;
      scan >> r;

      if(last_recur)
            return r * fraction;

      return r;
}

// Set up a rotation matrix
k3d::vector3 C1, C2, C3;

void set_rotation_matrix(double a, k3d::vector3 n)
{
      double cosa = cos(a);
      double sina = sin(a);

      double n11 = n[0] * n[0];
      double n22 = n[1] * n[1];
      double n33 = n[2] * n[2];

      double nxy = n[0] * n[1];
      double nxz = n[0] * n[2];
      double nyz = n[1] * n[2];

      C1[0] = n11 + (1.0 - n11) * cosa;
      C1[1] = nxy * (1.0 - cosa) - n[2] * sina;
      C1[2] = nxz * (1.0 - cosa) + n[1] * sina;

      C2[0] = nxy * (1.0 - cosa) + n[2] * sina;
      C2[1] = n22 + (1.0 - n22) * cosa;
      C2[2] = nyz * (1.0 - cosa) - n[0] * sina;

      C3[0] = nxz * (1.0 - cosa) - n[1] * sina;
      C3[1] = nyz * (1.0 - cosa) + n[0] * sina;
      C3[2] = n33 + (1.0 - n33) * cosa;
}

k3d::vector3 rotate(const k3d::vector3& In)
{
      return k3d::vector3(C1 * In, C2 * In, C3 * In);
}

// Process a production string and generate form
void L_draw(k3d::mesh* mesh)
{
      // Save values
      double thick_l = 0;
      double ang_l = 0;
      double dis_l = 0;
      double dis2_l = 0;
      double trope_l = 0;

      bool poly_on = false;

      // Setup vectors
      k3d::vector3 pos(0.0, 0.0, 0.0);
      k3d::vector3 fow(0.0, 0.0, 1.0);
      k3d::vector3 lef(0.0, 1.0, 0.0);
      k3d::vector3 upp(1.0, 0.0, 0.0);

      trope.Normalize();

      for(unsigned long i = 0; i < object_string.size(); i++)
            {
                  // Overflow
                  if(polcount > poly_limit)
                        break;

                  // The next char in the string
                  char next = object_string[i + 1];

                  // The current char in the string
                  switch(object_string[i])
                        {
                              default:
                                    break;

                              // Marks last recursion level during growing phase
                              case '@':
                                    last_recur = !last_recur;
                                    if(last_recur)
                                          {
                                                // Store all variables and do fraction
                                                thick_l = thick;
                                                ang_l = ang;
                                                dis_l = dis;
                                                dis2_l = dis2;
                                                trope_l = trope_amount;

                                                dis *= fraction;
                                                dis2 *= fraction;
                                                thick *= fraction;
                                                ang *= fraction;
                                                trope_amount *= fraction;
                                          }
                                    else
                                          {
                                                // Restore
                                                thick = thick_l;
                                                ang = ang_l;
                                                dis = dis_l;
                                                dis2 = dis2_l;
                                                trope_amount = trope_l;
                                          }
                              break;

                              case '+':
                                    save.ang = ang;
                                    if(next == '(')
                                          {
                                                ang = 0.017453 * parse_value(i);
                                                if(last_recur)
                                                      ang *= fraction;
                                          }

                                    set_rotation_matrix(-ang, upp);
                                    fow = rotate(fow);
                                    lef = rotate(lef);
                                    fow.Normalize();
                                    lef.Normalize();
                                    ang = save.ang;
                              break;

                              case '-':
                                    save.ang = ang;
                                    if(next == '(')
                                          {
                                                ang = 0.017453 * parse_value(i);
                                                if(last_recur)
                                                      ang *= fraction;
                                          }

                                    set_rotation_matrix(ang, upp);
                                    fow = rotate(fow);
                                    lef = rotate(lef);
                                    fow.Normalize();
                                    lef.Normalize();
                                    ang = save.ang;
                              break;

                              case '~':
                              {
                                    double r = 6.0;
                                    if(next == '(')
                                          r = 0.017453 * parse_value(i);
                                    else if(rand_set)
                                          r = 0.017453 * rand_amount;

                                    double a = Rnd() * r * 2.0 - r;
                                    set_rotation_matrix(a, upp);
                                    fow = rotate(fow);
                                    lef = rotate(lef);
                                    fow.Normalize();
                                    lef.Normalize();
                                    a = (Rnd() * r * 2.0) - r;
                                    set_rotation_matrix(a, lef);
                                    fow = rotate(fow);
                                    upp = rotate(upp);
                                    fow.Normalize();
                                    upp.Normalize();
                                    a = (Rnd() * r * 2.0) - r;
                                    set_rotation_matrix(a, fow);
                                    lef = rotate(lef);
                                    upp = rotate(upp);
                                    lef.Normalize();
                                    upp.Normalize();
                              }
                              break;

                              case 't':
                              {
                                    if((fow[0] == 0.0) && (fow[1] == 0.0))
                                          break;

                                    save.tr = tr;
                                    if(trope_set)
                                          tr = trope_amount;

                                    if(next == '(')
                                          {
                                                tr = parse_value(i);
                                                if(last_recur)
                                                      tr *= fraction;
                                          }

                                    trope = fow;
                                    trope[0] = -trope[0];
                                    trope[1] = -trope[1];
                                    trope[2] = 0.0;
                                    trope.Normalize();
                                    double r = tr * (fow * trope);
                                    set_rotation_matrix(-r, lef);
                                    fow = rotate(fow);
                                    upp = rotate(upp);
                                    fow.Normalize();
                                    upp.Normalize();
                                    tr = save.tr;
                              }
                              break;

                              case '$':
                              {
                                    k3d::vector3 v = fow - sky;
                                    if(v.Length() == 0.0)
                                          break;

                                    lef = fow ^ sky;
                                    upp = fow ^ lef;
                                    if(upp[2] < 0.0)
                                          {
                                                upp = -upp;
                                                lef = -lef;
                                          }
                              }
                              break;

                              case '&':
                                    save.ang = ang;
                                    if(next == '(')
                                          {
                                                ang = 0.017453 * parse_value(i);
                                                 if(last_recur)
                                                ang *= fraction;
                                          }

                                    set_rotation_matrix(ang, lef);
                                    fow = rotate(fow);
                                    upp = rotate(upp);
                                    fow.Normalize();
                                    upp.Normalize();
                                    ang = save.ang;
                              break;

                              case '^':
                                    save.ang = ang;
                                    if(next == '(')
                                          {
                                                ang = 0.017453 * parse_value(i);
                                                if(last_recur)
                                                      ang *= fraction;
                                          }

                                    set_rotation_matrix(-ang, lef);
                                    fow = rotate(fow);
                                    upp = rotate(upp);
                                    fow.Normalize();
                                    upp.Normalize();
                                    ang = save.ang;
                              break;

                              case '<':
                                    save.ang = ang;
                                    if(next == '(')
                                          {
                                                ang = 0.017453 * parse_value(i);
                                                if(last_recur)
                                                      ang *= fraction;
                                          }

                                    set_rotation_matrix(-ang, fow);
                                    lef = rotate(lef);
                                    upp = rotate(upp);
                                    lef.Normalize();
                                    upp.Normalize();
                                    ang = save.ang;
                              break;

                              case '>':
                                    save.ang = ang;
                                    if(next == '(')
                                          {
                                                ang = 0.017453 * parse_value(i);
                                                if(last_recur)
                                                      ang *= fraction;
                                          }

                                    set_rotation_matrix(ang, fow);
                                    lef = rotate(lef);
                                    upp = rotate(upp);
                                    lef.Normalize();
                                    upp.Normalize();
                                    ang = save.ang;
                              break;

                              case '%':
                                    set_rotation_matrix(3.141592654, fow);
                                    lef = rotate(lef);
                                    upp = rotate(upp);
                                    lef.Normalize();
                                    upp.Normalize();
                              break;

                              case '|':
                                    set_rotation_matrix(3.141592654, upp);
                                    fow = rotate(fow);
                                    lef = rotate(lef);
                                    fow.Normalize();
                                    lef.Normalize();
                              break;

                              case '!':
                                    if(next == '(')
                                          {
                                                if(last_recur)
                                                      thick *= 1.0 + fraction * (parse_value(i) - 1.0);
                                                else
                                                      thick *= parse_value(i);
                                          }
                                    else
                                          {
                                                if(last_recur)
                                                      thick *= 1.0 + fraction * (0.7 - 1.0);
                                                else
                                                      thick *= 0.7;
                                          }
                              break;

                              case '?':
                                    if(next == '(')
                                          {
                                                if(last_recur)
                                                      thick *= 1.0 + fraction * (parse_value(i) - 1.0);
                                                else
                                                      thick *= parse_value(i);
                                          }
                                    else
                                          {
                                                if(last_recur)
                                                      thick /= 1.0 + fraction * (0.7 - 1.0);
                                                else
                                                      thick /= 0.7;
                                          }
                              break;

                              case ':':
                                    if(next == '(')
                                          {
                                                if(last_recur)
                                                      ang *= 1.0 + fraction * (parse_value(i) - 1.0);
                                                else
                                                      ang *= parse_value(i);
                                          }
                                    else
                                          {
                                                if(last_recur)
                                                      ang *= 1.0 + fraction * (0.9 - 1.0);
                                                else
                                                      ang *= 0.9;
                                          }
                              break;

                              case ';':
                                    if(next == '(')
                                          {
                                                if(last_recur)
                                                      ang *= 1.0 + fraction * (parse_value(i) - 1.0);
                                                else
                                                      ang *= parse_value(i);
                                          }
                                    else
                                          {
                                                if(last_recur)
                                                      ang /= 1.0 + fraction * (0.9 - 1.0);
                                                else
                                                      ang /= 0.9;
                                          }
                              break;

                              case '\'':
                                    if(next == '(')
                                          {
                                                double r = parse_value(i);
                                                if(last_recur)
                                                      {
                                                            dis *= 1.0 + fraction * (r - 1.0);
                                                            dis2 *= 1.0 + fraction * (r - 1.0);
                                                      }
                                                else
                                                      {
                                                            dis *= r;
                                                            dis2 *= r;
                                                      }
                                          }
                                    else
                                          {
                                                if(last_recur)
                                                      {
                                                            dis *= 1.0 + fraction * (0.9 - 1.0);
                                                            dis2 *= 1.0 + fraction * (0.9 - 1.0);
                                                      }
                                                else
                                                      {
                                                            dis *= 0.9;
                                                            dis2 *= 0.9;
                                                      }
                                          }
                              break;

                              case '"':
                                    if(next == '(')
                                          {
                                                double r = parse_value(i);
                                                if(last_recur)
                                                      {
                                                            dis *= 1.0 + fraction * (r - 1.0);
                                                            dis2 *= 1.0 + fraction * (r - 1.0);
                                                      }
                                                else
                                                      {
                                                            dis *= r;
                                                            dis2 *= r;
                                                      }
                                          }
                                    else
                                          {
                                                if(last_recur)
                                                      {
                                                            dis /= 1.0 + fraction * (0.9 - 1.0);
                                                            dis2 /= 1.0 + fraction * (0.9 - 1.0);
                                                      }
                                                else
                                                      {
                                                            dis /= 0.9;
                                                            dis2 /= 0.9;
                                                      }
                                          }
                              break;

                              case 'Z':
                              {
                                    save.dis2 = dis2;
                                    if(next == '(')
                                          {
                                                dis2 = parse_value(i);
                                                if(last_recur)
                                                      dis2 *= fraction;
                                          }

                                    k3d::vector3 end = pos + dis2 * fow;
                                    if(closed_form)
                                          add_cylinder(pos, end, upp, col, mesh);
                                    else
                                          add_cube(pos, end, upp, col, mesh);

                                    pos = end;
                                    dis2 = save.dis2;
                              }
                              break;

                              case 'F':
                              {
                                    save.dis = dis;
                                    if(next == '(')
                                          {
                                                dis = parse_value(i);
                                                if(last_recur)
                                                      dis *= fraction;
                                          }

                                    k3d::vector3 end = pos + dis * fow;
                                    if(closed_form)
                                          add_cylinder(pos, end, upp, col, mesh);
                                    else
                                          add_cube(pos, end, upp, col, mesh);

                                    pos = end;
                                    dis = save.dis;
                              }
                              break;

                              case '[':
                              {
                                    s_rec new_rec;
                                    new_rec.pos = pos;
                                    new_rec.fow = fow;
                                    new_rec.lef = lef;
                                    new_rec.upp = upp;
                                    new_rec.col = col;
                                    new_rec.dis = dis;
                                    new_rec.dis2 = dis2;
                                    new_rec.ang = ang;
                                    new_rec.thick = thick;
                                    new_rec.tr = tr;

                                    if(closed_form)
                                          {
                                                new_rec.last = last;
                                                new_rec.last_col = last_col;
                                                for(unsigned long j = 0; j < 8; j++)
                                                      new_rec.last_v[j] = last_v[j];
                                          }

                                    if(stack.size() < max_stack_size)
                                          stack.push(new_rec);
                              }
                              break;

                              case ']':
                              {
                                    if(!stack.size())
                                          break;

                                    s_rec old_rec = stack.top();
                                    pos = old_rec.pos;
                                    fow = old_rec.fow;
                                    lef = old_rec.lef;
                                    upp = old_rec.upp;
                                    col = old_rec.col;
                                    dis = old_rec.dis;
                                    dis2 = old_rec.dis2;
                                    ang = old_rec.ang;
                                    thick = old_rec.thick;
                                    tr = old_rec.tr;
                                    if(closed_form)
                                          {
                                                last = old_rec.last;
                                                last_col = old_rec.last_col;
                                                for(unsigned long j = 0; j < 8; j++)
                                                      last_v[j] = old_rec.last_v[j];
                                          }

                                    stack.pop();
                              }
                              break;

                              case '{':
                                    if(poly_on)
                                          {
                                                vectors_t new_rec = vertices;
                                                if(pstack.size() < max_stack_size)
                                                      pstack.push(new_rec);
                                          }

                                    poly_on = true;

                                    vertices.clear();
                                    vertices.push_back(pos);
                              break;

                              case 'f':
                                    save.dis = dis;
                                    if(next == '(')
                                          {
                                                dis = parse_value(i);
                                                if(last_recur)
                                                      dis *= fraction;
                                          }

                                    pos = pos + dis * fow;
                                    if(poly_on)
                                          vertices.push_back(pos);

                                    dis = save.dis;
                              break;

                              case '.':
                                    if(poly_on)
                                          vertices.push_back(pos);
                              break;

                              case 'g':
                                    save.dis = dis;
                                    if(next == '(')
                                          {
                                                dis = parse_value(i);
                                                if(last_recur)
                                                      dis *= fraction;
                                          }

                                    pos = pos + dis * fow;
                                    dis = save.dis;
                              break;

                              case 'z':
                                    save.dis2 = dis2;
                                    if(next == '(')
                                          {
                                                dis2 = parse_value(i);
                                                if(last_recur)
                                                      dis2 *= fraction;
                                          }

                                    pos = pos + dis2 * fow;
                                    if(poly_on)
                                          vertices.push_back(pos);

                                    dis2 = save.dis2;
                              break;

                              case '}':
                                    polygons.clear();
                                    if(vertices.size() > 3)
                                          {
                                                for(unsigned long j = 1; j < vertices.size() - 1; j++)
                                                      polygons.push_back(polygon(0, j, j + 1, j + 1));

                                                add_geometry(col, mesh);
                                          }

                                    poly_on = false;
                                    if(pstack.size() > 0)
                                          {
                                                vertices.clear();

                                                if(!pstack.size())
                                                      break;

                                                vertices = pstack.top();
                                                pstack.pop();

                                                poly_on = true;
                                          }
                              break;

                              case 'c':
                                    if(next == '(')
                                          col = (unsigned long)parse_value(i);
                                    else
                                          col++;
                              break;
                        }
            }
}

bool l_parser(const unsigned long random_seed, const bool closedform, const double trope, const unsigned long mutations, const unsigned long mutation_seed, const unsigned long maximal_stack_size, k3d::mesh* mesh)
{
      // Make sure we have a polyhedron to fill
      return_val_if_fail(mesh->polyhedra.size(), false);

      // set minimum thickness
      //min_thick = ;

      // set amount of trope
      trope_amount = trope;

      // create closed connected cylinders
      closed_form = closedform;

      // Execute mutations
      srand(mutation_seed);
      for(unsigned long i = 0; i < mutations; i++)
            // Perform mutations on stored rule set
            L_mutate();

      // Create L-system production string
      L_system();

      // Parse production string and create geometry
      srand(random_seed);
      max_stack_size = maximal_stack_size;
      L_draw(mesh);

      return true;
}

} // namespace lparser

/////////////////////////////////////////////////////////////////////////////
// l_parser_implementation

class l_parser_implementation :
      public k3d::material_collection<k3d::mesh_source<k3d::persistent<k3d::object> > >
{
      typedef k3d::material_collection<k3d::mesh_source<k3d::persistent<k3d::object> > > base;

public:
      l_parser_implementation(k3d::idocument& Document) :
            base(Document),
            m_file_path(k3d::init_name("file") + k3d::init_description("File path [string]") + k3d::init_value(boost::filesystem::path(k3d::application().share_path() / "lsystem/abop-nested-polygon-leaves.ls")) + k3d::init_document(Document)),
            m_recursion(k3d::init_name("growth") + k3d::init_description("Growth value [number]") + k3d::init_value(5.0) + k3d::init_precision(2) + k3d::init_step_increment(0.1) + k3d::init_constraint(k3d::constraint::minimum(1.0)) + k3d::init_units(typeid(k3d::measurement::scalar)) + k3d::init_document(Document)),
            m_basic_angle(k3d::init_name("basic_angle") + k3d::init_description("Basic Angle [number]") + k3d::init_value(10.0) + k3d::init_precision(2) + k3d::init_step_increment(1.0) + k3d::init_units(typeid(k3d::measurement::scalar)) + k3d::init_document(Document)),
            m_thickness(k3d::init_name("thickness") + k3d::init_description("Thickness [number]") + k3d::init_value(50.0) + k3d::init_precision(2) + k3d::init_step_increment(1.0) + k3d::init_units(typeid(k3d::measurement::scalar)) + k3d::init_document(Document)),
            m_random_seed(k3d::init_name("random_seed") + k3d::init_description("Random Seed [number]") + k3d::init_value(0) + k3d::init_precision(0) + k3d::init_step_increment(1) + k3d::init_units(typeid(k3d::measurement::scalar)) + k3d::init_document(Document)),
            m_size(k3d::init_name("size") + k3d::init_description("Size [number]") + k3d::init_value(5.0) + k3d::init_precision(2) + k3d::init_step_increment(0.1) + k3d::init_units(typeid(k3d::measurement::scalar)) + k3d::init_document(Document)),
            m_closed_form(k3d::init_name("closed_form") + k3d::init_description("Closed form [boolean]") + k3d::init_value(true) + k3d::init_document(Document)),
            m_mutations(k3d::init_name("mutations") + k3d::init_description("Mutations [number]") + k3d::init_value(0) + k3d::init_precision(0) + k3d::init_step_increment(1) + k3d::init_units(typeid(k3d::measurement::scalar)) + k3d::init_document(Document)),
            m_mutation_seed(k3d::init_name("mutation_seed") + k3d::init_description("Mutation Seed [number]") + k3d::init_value(0) + k3d::init_precision(0) + k3d::init_step_increment(1) + k3d::init_units(typeid(k3d::measurement::scalar)) + k3d::init_document(Document)),
            m_max_stack_size(k3d::init_name("max_stack_size") + k3d::init_description("Max Stack Size [number]") + k3d::init_value(1000) + k3d::init_precision(0) + k3d::init_step_increment(1) + k3d::init_units(typeid(k3d::measurement::scalar)) + k3d::init_document(Document))
      {
            enable_serialization(k3d::persistence::proxy(m_file_path));
            enable_serialization(k3d::persistence::proxy(m_recursion));
            enable_serialization(k3d::persistence::proxy(m_basic_angle));
            enable_serialization(k3d::persistence::proxy(m_thickness));
            enable_serialization(k3d::persistence::proxy(m_random_seed));
            enable_serialization(k3d::persistence::proxy(m_size));
            enable_serialization(k3d::persistence::proxy(m_closed_form));
            enable_serialization(k3d::persistence::proxy(m_mutations));
            enable_serialization(k3d::persistence::proxy(m_mutation_seed));
            enable_serialization(k3d::persistence::proxy(m_max_stack_size));

            register_property(m_file_path);
            register_property(m_recursion);
            register_property(m_basic_angle);
            register_property(m_thickness);
            register_property(m_random_seed);
            register_property(m_size);
            register_property(m_closed_form);
            register_property(m_mutations);
            register_property(m_mutation_seed);
            register_property(m_max_stack_size);

            m_material.changed_signal().connect(SigC::slot(*this, &l_parser_implementation::on_reset_geometry));

            m_file_path.changed_signal().connect(SigC::slot(*this, &l_parser_implementation::on_new_file));
            m_recursion.changed_signal().connect(SigC::slot(*this, &l_parser_implementation::on_reset_geometry));
            m_basic_angle.changed_signal().connect(SigC::slot(*this, &l_parser_implementation::on_reset_geometry));
            m_thickness.changed_signal().connect(SigC::slot(*this, &l_parser_implementation::on_reset_geometry));
            m_random_seed.changed_signal().connect(SigC::slot(*this, &l_parser_implementation::on_reset_geometry));
            m_size.changed_signal().connect(SigC::slot(*this, &l_parser_implementation::on_reset_geometry));
            m_closed_form.changed_signal().connect(SigC::slot(*this, &l_parser_implementation::on_reset_geometry));
            m_mutations.changed_signal().connect(SigC::slot(*this, &l_parser_implementation::on_reset_geometry));
            m_mutation_seed.changed_signal().connect(SigC::slot(*this, &l_parser_implementation::on_reset_geometry));
            m_max_stack_size.changed_signal().connect(SigC::slot(*this, &l_parser_implementation::on_reset_geometry));

            m_output_mesh.need_data_signal().connect(SigC::slot(*this, &l_parser_implementation::on_create_geometry));

            // Init with default example
            init_lsystem();
      }

      void init_lsystem()
      {
            // Load configuration file
            const boost::filesystem::path file_path = m_file_path.property_value();
            double recursion, basic_angle, thickness;
            if(!lparser::load_configuration_values(file_path, recursion, basic_angle, thickness))
                  return;

            // Set configuration's default recursion values
            k3d::set_property_value(m_recursion, recursion);
            k3d::set_property_value(m_basic_angle, basic_angle);
            k3d::set_property_value(m_thickness, thickness);

            // Reset bounding box
            lparser::bounding_box = k3d::bounding_box();
            lparser::bbox_x = lparser::bbox_y = lparser::bbox_z = 0;
      }

      void on_new_file()
      {
            init_lsystem();
            on_reset_geometry();
      }

      void on_reset_geometry()
      {
            m_output_mesh.reset();
      }

      k3d::mesh* on_create_geometry()
      {
            const double recursion = m_recursion.property_value();
            const double basic_angle = m_basic_angle.property_value();
            const double thickness = m_thickness.property_value();
            const unsigned long random_seed = m_random_seed.property_value();
            const double size = m_size.property_value();
            const bool closedform = m_closed_form.property_value();
            const unsigned long mutations = m_mutations.property_value();
            const unsigned long mutation_seed = m_mutation_seed.property_value();
            const unsigned long max_stack_size = m_max_stack_size.property_value();

            // Load configuration file
            const boost::filesystem::path file_path = m_file_path.property_value();
            if(!lparser::load_configuration_rules(recursion, basic_angle, thickness, file_path))
                  return 0;

            // Create geometry ...
            std::auto_ptr<k3d::mesh> mesh(new k3d::mesh());
            k3d::polyhedron* polyhedron = new k3d::polyhedron();
            return_val_if_fail(polyhedron, 0);
            mesh->polyhedra.push_back(polyhedron);
            lparser::l_parser(random_seed, closedform, 0, mutations, mutation_seed, max_stack_size, mesh.get());

            // Cache first bounding box to allow growth
            if(lparser::bbox_x == 0 && lparser::bbox_y == 0 && lparser::bbox_z == 0)
                  {
                        lparser::bbox_x = lparser::bounding_box.width();
                        lparser::bbox_y = lparser::bounding_box.height();
                        lparser::bbox_z = lparser::bounding_box.depth();
                  }

            // Resize ...
            double bbox_size = std::max(std::max(lparser::bbox_x, lparser::bbox_y), lparser::bbox_z);
            if(bbox_size > 0)
                  {
                        double new_size = 1 / bbox_size * size;
                        for(k3d::mesh::points_t::const_iterator point = mesh->points.begin(); point != mesh->points.end(); point++)
                              (*point)->position *= new_size;
                  }

            polyhedron->material = m_material.interface();

            return_val_if_fail(is_valid(*polyhedron), 0);
            //assert_warning(is_solid(polyhedron));

            return mesh.release();
      }

      k3d::iplugin_factory& factory()
      {
            return get_factory();
      }

      static k3d::iplugin_factory& get_factory()
      {
            static k3d::plugin_factory<k3d::document_plugin<l_parser_implementation>, k3d::interface_list<k3d::imesh_source > > factory(
                  k3d::uuid(0xa637e99d, 0x707c4342, 0x8c6d4d15, 0x78c9054a),
                  "LSystemParser",
                  "Generates a L-System object from a configuration file",
                  "Objects",
                  k3d::iplugin_factory::EXPERIMENTAL);

            return factory;
      }

private:
      k3d_data_property(boost::filesystem::path, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::no_constraint) m_file_path;
      k3d_measurement_property(double, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::with_constraint) m_recursion;
      k3d_measurement_property(double, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::no_constraint) m_basic_angle;
      k3d_measurement_property(double, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::no_constraint) m_thickness;
      k3d_measurement_property(unsigned long, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::no_constraint) m_random_seed;
      k3d_measurement_property(double, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::no_constraint) m_size;
      k3d_data_property(bool, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::no_constraint) m_closed_form;
      k3d_measurement_property(unsigned long, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::no_constraint) m_mutations;
      k3d_measurement_property(unsigned long, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::no_constraint) m_mutation_seed;
      k3d_measurement_property(unsigned long, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::no_constraint) m_max_stack_size;
};

} // namespace libk3dlsystem

K3D_MODULE_START(k3d::uuid(0xca6ffe7d, 0x5a7a4485, 0x979414de, 0xb8b1006a), Registry)
      Registry.register_factory(libk3dlsystem::l_parser_implementation::get_factory());
K3D_MODULE_END



Generated by  Doxygen 1.6.0   Back to index