diff --git a/src/VirtualLeaf.cpp b/src/VirtualLeaf.cpp
new file mode 100644
--- /dev/null
+++ b/src/VirtualLeaf.cpp
@@ -0,0 +1,548 @@
+/*
+ *
+ * This file is part of the Virtual Leaf.
+ *
+ * The Virtual Leaf 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The Virtual Leaf 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 the Virtual Leaf. If not, see .
+ *
+ * Copyright 2010 Roeland Merks.
+ *
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "mesh.h"
+#include "parameter.h"
+#include "random.h"
+#include "pi.h"
+#include "cellitem.h"
+#include "canvas.h"
+#include "cell.h"
+#include "output.h"
+#include
+#include
+#include
+#include
+#include
+#include
+//Added by qt3to4:
+#include
+
+#include
+#include
+
+#ifdef HAVE_QWT
+#include "data_plot.h"
+#endif
+#include
+#include
+#include
+#include "simplugin.h"
+#include
+#include
+#include "modelcatalogue.h"
+
+/* #define _xstr_(s) _str_(s)
+#define _str_(s) #s
+#include _xstr_(REACTIONS_HEADER)
+*/
+
+static const std::string _module_id("$Id$");
+
+extern Parameter par;
+
+MainBase *main_window = 0;
+//double auxin_account = 0.;
+
+
+
+#ifdef XFIGGRAPHICS
+#define TIMESTEP double Graphics::TimeStep(void)
+#endif
+
+class PrintNode {
+public:
+ void operator() (const Node &n) const
+ {
+ cerr << n.Index() << ": " << n << endl;
+ }
+};
+
+
+class EdgeSource {
+
+public:
+ void operator() (Cell &c) {
+
+ if (c.AtBoundaryP()) {
+ cerr << "Cell " << c.Index() << " is a source cell.\n";
+ c.SetSource(0,par.source);
+ } else {
+ cerr << "Cell " << c.Index() << " is _not_ a source cell.\n";
+ }
+ }
+
+};
+
+
+
+class CellInfo {
+public:
+ void operator() (Cell &c,std::ostream &os) const {
+ os << "Cell " << c.index << " says: " << endl;
+ os << "c.nodes.size() = " << c.nodes.size() << endl;
+ for (list::iterator i=c.nodes.begin();
+ i!=c.nodes.end();
+ i++) {
+ cerr << (*i)->Index() << " ";
+ }
+ cerr << endl;
+ }
+};
+
+double PINSum(Cell &c) {
+
+ return c.Chemical(1) + c.SumTransporters(1);// + c.ReduceCellAndWalls( complex_PijAj );
+
+}
+
+
+class DrawCell {
+public:
+ void operator() (Cell &c,QGraphicsScene &canvas, MainBase &m) const {
+ if (m.ShowBorderCellsP() || c.Boundary()==Cell::None) {
+ if (!m.ShowBoundaryOnlyP() && !m.HideCellsP())
+ if (m.ShowToolTipsP()) {
+ QString info_string=QString("Cell %1, chemicals: ( %2, %3, %4, %5, %6)\n %7 of PIN1 at walls.\n Area is %8\n PIN sum is %9\n Circumference is %10\n Boundary type is %11").arg(c.Index()).arg(c.Chemical(0)).arg(c.Chemical(1)).arg(c.Chemical(2)).arg(c.Chemical(3)).arg(c.Chemical(4)).arg(c.SumTransporters(1)).arg(c.Area()).arg(PINSum(c)).arg(c.Circumference()).arg(c.BoundaryStr());
+
+ info_string += "\n" + c.printednodelist();
+
+ c.Draw(&canvas, info_string);
+ } else {
+ c.Draw(&canvas);
+ }
+ if (m.ShowCentersP())
+ c.DrawCenter(&canvas);
+ if (m.ShowFluxesP())
+ c.DrawFluxes(&canvas, par.arrowsize);
+
+ }
+
+ }
+
+};
+
+Mesh mesh;
+bool batch=false;
+
+
+void MainBase::Plot(int resize_stride) {
+
+ clear();
+
+
+ static int count=0;
+ if (resize_stride) {
+ if ( !((++count)%resize_stride) ) {
+ FitLeafToCanvas();
+ }
+ }
+ mesh.LoopCells(DrawCell(),canvas,*this);
+
+ if (ShowNodeNumbersP())
+ mesh.LoopNodes( bind2nd (mem_fun_ref ( &Node::DrawIndex), &canvas ) ) ;
+ if (ShowCellNumbersP())
+ mesh.LoopCells( bind2nd (mem_fun_ref ( &Cell::DrawIndex), &canvas ) ) ;
+
+ if (ShowCellAxesP())
+ mesh.LoopCells( bind2nd (mem_fun_ref ( &Cell::DrawAxis), &canvas ) );
+
+ if (ShowCellStrainP())
+ mesh.LoopCells( bind2nd (mem_fun_ref ( &Cell::DrawStrain), &canvas ) );
+
+ if (ShowWallsP())
+
+ mesh.LoopWalls( bind2nd( mem_fun_ref( &Wall::Draw ), &canvas ) );
+
+ if (ShowApoplastsP())
+ mesh.LoopWalls( bind2nd( mem_fun_ref( &Wall::DrawApoplast ), &canvas ) );
+
+ if (ShowMeshP())
+ mesh.DrawNodes(&canvas);
+
+ if (ShowBoundaryOnlyP())
+ mesh.DrawBoundary(&canvas);
+
+
+ if ( ( batch || MovieFramesP() )) {
+
+ static int frame = 0;
+ // frame numbers are sequential for the most frequently written file type.
+ // for the less frequently written file type they match the other type
+ if (!(count%par.storage_stride) ) {
+
+ stringstream fname;
+ fname << par.datadir << "/leaf.";
+ fname.fill('0');
+ fname.width(6);
+
+ /*
+ fname << frame << ".pdf";
+ if (par.storage_stride <= par.xml_storage_stride) {
+ frame++;
+ }
+
+ // Write high-res JPG snapshot every plot step
+ Save(fname.str().c_str(), "PDF");
+ */
+
+ fname << frame << ".jpg";
+ if (par.storage_stride <= par.xml_storage_stride) {
+ frame++;
+ }
+
+ // Write high-res JPG snapshot every plot step
+ Save(fname.str().c_str(), "JPEG",1024,768);
+
+ }
+
+ if (!(count%par.xml_storage_stride)) {
+ stringstream fname;
+ fname << par.datadir << "/leaf.";
+ fname.fill('0');
+ fname.width(6);
+ fname << frame << ".xml";
+
+ if (par.xml_storage_stride < par.storage_stride) {
+ frame++;
+ }
+ // Write XML file every ten plot steps
+ mesh.XMLSave(fname.str().c_str(), XMLSettingsTree());
+ }
+
+ }
+}
+
+
+
+INIT {
+
+ //mesh.SetSimPlugin(plugin);
+ if (leaffile) {
+ xmlNode *settings;
+ mesh.XMLRead(leaffile, &settings);
+
+ main_window->XMLReadSettings(settings);
+ xmlFree(settings);
+ main_window->UserMessage(QString("Ready. Time is %1").arg(mesh.getTimeHours().c_str()));
+
+ } else {
+ mesh.StandardInit();
+ }
+}
+
+TIMESTEP {
+
+ static int i=0;
+ static int t=0;
+ static int ncells;
+
+ if (!batch) {
+ UserMessage(QString("Time: %1").arg(mesh.getTimeHours().c_str()),0);
+ }
+
+ ncells=mesh.NCells();
+
+
+ double dh;
+
+ if(DynamicCellsP()) {
+ dh = mesh.DisplaceNodes();
+
+ // Only allow for node insertion, cell division and cell growth
+ // if the system has equillibrized
+ // i.e. cell wall tension equillibrization is much faster
+ // than biological processes, including division, cell wall yielding
+ // and cell expansion
+ mesh.InsertNodes(); // (this amounts to cell wall yielding)
+
+ if ( (-dh) < par.energy_threshold) {
+
+ mesh.IncreaseCellCapacityIfNecessary();
+ mesh.DoCellHouseKeeping();
+ //mesh.LoopCurrentCells(mem_fun(&plugin->CellHouseKeeping)); // this includes cell division
+
+ // Reaction diffusion
+ /*CelltoCellTransport *transport_f = &TestPlugin::CelltoCellTransport;
+ CellReaction *cellreaction_f = new plugin->CellDynamics();
+ WallReaction *wall_f = new WallDynamics();*/
+
+ mesh.ReactDiffuse(par.rd_dt);
+
+
+ t++;
+
+ Plot(par.resize_stride);
+
+ /*QVector< QPair > angles=mesh.VertexAnglesValues();
+ QString afname=QString("Angles/anglesvalues%1.dat").arg(t,6,10,QChar('0'));
+ ofstream af(afname.toStdString().c_str());
+ */
+
+ /*for (QVector< QPair >::const_iterator v=angles.begin();
+ v!=angles.end();
+ v++) {
+ af << v->first << " " << v->second << endl;
+ }
+ */
+ }
+
+ } else {
+
+ /* TransportFunction *transport_f = new CelltoCellTransport();
+ CellReaction *cellreaction_f = new CellDynamics();
+ WallReaction *wall_f = new WallDynamics();
+
+ mesh.ReactDiffuse_New(transport_f, cellreaction_f, wall_f, par.rd_dt);*/
+ mesh.ReactDiffuse(par.rd_dt);
+
+ Plot(par.resize_stride);
+
+ }
+
+
+
+
+
+ i++;
+ return mesh.getTime();
+
+}
+
+
+
+/* Called if a cell is clicked */
+void Cell::OnClick(QMouseEvent *e) {
+ /* #ifdef HAVE_QWT
+ // Launch DataPlot window
+ QStringList curvenames;
+ for (int i=0;iOnClick(*this);
+}
+
+
+/* Custom message handler - Default appends a newline character to the end of each line. */
+ void vlMessageOutput(QtMsgType type, const char *msg)
+ {
+ switch (type) {
+ case QtDebugMsg:
+ //fprintf(stderr, "Debug: %s\n", msg);
+ cerr << msg << flush;
+ break;
+ case QtWarningMsg:
+ //fprintf(stderr, "Warning: %s\n", msg);
+ cerr << "Warning: " << msg << flush;
+ break;
+ case QtCriticalMsg:
+ fprintf(stderr, "Critical: %s\n", msg);
+ cerr << "Critical: " << msg << flush;
+ break;
+ case QtFatalMsg:
+ //fprintf(stderr, "Fatal: %s\n", msg);
+ cerr << "Fatal: " << msg << flush;
+ abort();
+ }
+ }
+
+
+Parameter par;
+
+int main(int argc,char **argv) {
+
+ try {
+
+
+ int c;
+
+
+ char *leaffile=0;
+
+
+ while (1) {
+
+ //int this_option_optind = optind ? optind : 1;
+ int option_index = 0;
+ static struct option long_options[] = {
+ {"batch", 0, 0, 0},
+ {"leaffile", 2, 0, 0}
+ };
+
+ // short option 'p' creates trouble for non-commandline usage on MacOSX. Option -p changed to -P (capital)
+ static char *short_options = "bl";
+ c = getopt_long (argc, argv, "bl:",
+ long_options, &option_index);
+ if (c == -1)
+ break;
+
+
+ if (c==0) {
+ printf ("option %s", long_options[option_index].name);
+ if (optarg)
+ printf (" with arg %s", optarg);
+ printf ("\n");
+
+ c = short_options[option_index];
+ }
+
+ switch (c) {
+ case 'b':
+ cerr << "Running in batch mode\n";
+ batch=true;
+ break;
+
+ case 'l':
+ leaffile=strdup(optarg);
+ if (!leaffile) {
+ throw("Out of memory");
+ }
+ printf("Reading leaf state file '%s'\n", leaffile);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+
+ if (optind < argc) {
+ printf ("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf ("%s ", argv[optind++]);
+ printf ("\n");
+ }
+
+ bool useGUI = !batch;
+ qInstallMsgHandler(vlMessageOutput); // custom message handler
+ QApplication app(argc,argv,useGUI);
+
+
+
+ QPalette tooltippalette = QToolTip::palette();
+ QColor transparentcolor = QColor(tooltippalette.brush(QPalette::Window).color());
+
+ tooltippalette.setBrush (QPalette::Window, QBrush (transparentcolor) );
+ QToolTip::setPalette( tooltippalette );
+
+ QGraphicsScene canvas(0,0,8000,6000);
+
+
+ if (useGUI) {
+ main_window=new Main(canvas, mesh);
+ if ( QApplication::desktop()->width() > ((Main *)main_window)->width() + 10
+ && QApplication::desktop()->height() > ((Main *)main_window)->height() +30 ) {
+
+ ((Main *)main_window)->show();
+ ((Main *)main_window)->resize( ((Main *)main_window)->sizeHint());
+ } else {
+ ((Main *)main_window)->showMaximized();
+ }
+ } else {
+ main_window=new MainBase(canvas, mesh);
+
+ }
+
+
+
+ canvas.setSceneRect(QRectF());
+ if (!batch) {
+ QObject::connect( qApp, SIGNAL(lastWindowClosed()), qApp, SLOT(quit()) );
+ }
+
+ // Load plugins
+ /*QVector plugins = LoadPlugins();
+ InstallPlugin(plugins[0], main_window);
+
+ cerr << "List of models:" << endl;
+ foreach (SimPluginInterface *p, plugins) {
+ cerr << p->ModelID().toStdString() << endl;
+ }
+ */
+
+
+
+ ModelCatalogue model_catalogue(&mesh, (Main *)main_window);
+ model_catalogue.PopulateModelMenu();
+ model_catalogue.InstallFirstModel();
+
+ //main_window->Init(leaffile);
+
+ Cell::SetMagnification(1);
+ Cell::setOffset(0,0);
+
+ main_window->FitLeafToCanvas();
+
+
+
+ main_window->Plot();
+
+
+
+ if (batch) {
+ double t=0.;
+ do {
+ t = main_window->TimeStep();
+ } while (t < par.maxt);
+
+ } else
+ return app.exec();
+
+
+ } catch (const char *message) {
+ if (batch) {
+ cerr << "Exception caught:" << endl;
+ cerr << message << endl;
+ abort();
+ } else {
+ QString qmess=QString("Exception caught: %1").arg(message);
+ QMessageBox::critical(0, "Critical Error", qmess);
+ abort();
+ }
+ } catch (ios_base::failure) {
+ stringstream error_message;
+ error_message << "I/O failure: " << strerror(errno);
+ if (batch) {
+ cerr << error_message.str() <