Changeset - 15d600891648
[Not reviewed]
default
! ! !
Michael Guravage - 15 years ago 2010-06-24 15:22:58
michael.guravage@cwi.nl
In DrawCell class (VirtualLeaf.cpp) - iterate over NChem to construct info_string. Additional cleanup.

--
user: Michael Guravage <michael.guravage@cwi.nl>
branch 'default'
changed src/ChangeLog
changed src/Neighbor.cpp
changed src/Neighbor.h
changed src/OptionFileDialog.cpp
changed src/OptionFileDialog.h
changed src/UniqueMessage.cpp
changed src/UniqueMessage.h
changed src/VirtualLeaf.cpp
changed src/VirtualLeaf.pro
changed src/build_models/plugin_auxingrowth.pro
changed src/build_models/plugin_meinhardt.pro
changed src/build_models/plugin_test.pro
changed src/canvas.cpp
changed src/canvas.h
changed src/cell.cpp
changed src/cell.h
changed src/cellbase.cpp
changed src/cellbase.h
changed src/cellitem.cpp
changed src/cellitem.h
changed src/forwardeuler.cpp
changed src/forwardeuler.h
changed src/infobar.h
changed src/libplugin.pro
changed src/mainbase.cpp
changed src/mainbase.h
changed src/matrix.cpp
changed src/matrix.h
changed src/mesh.cpp
changed src/mesh.h
changed src/miscq.cpp
changed src/miscq.h
changed src/modelcatalogue.cpp
changed src/modelcatalogue.h
changed src/node.cpp
changed src/node.h
changed src/nodeitem.cpp
changed src/nodeitem.h
changed src/nodeset.cpp
changed src/nodeset.h
changed src/output.cpp
changed src/output.h
changed src/parameter.cpp
changed src/parameter.h
changed src/pardialog.cpp
changed src/parse.cpp
changed src/parse.h
changed src/pi.h
changed src/qcanvasarrow.h
changed src/random.cpp
changed src/random.h
changed src/rungekutta.cpp
changed src/rungekutta.h
changed src/simitembase.cpp
changed src/simitembase.h
changed src/simplugin.h
changed src/sqr.h
changed src/tiny.h
changed src/transporterdialog.cpp
changed src/transporterdialog.h
changed src/vector.cpp
changed src/vector.h
changed src/wall.cpp
changed src/wall.h
changed src/wallbase.cpp
changed src/wallbase.h
changed src/wallitem.cpp
changed src/wallitem.h
changed src/warning.cpp
changed src/warning.h
changed src/xmlwrite.cpp
changed src/xmlwrite.h
28 files changed:
0 comments (0 inline, 0 general)
src/ChangeLog
Show inline comments
 
2010-06-24    <guravage@caterpie.sen.cwi.nl>
 

	
 
	* VirtualLeaf.cpp (DrawCell): Iterate over NChem to construct info_string.
 

	
 
2010-06-23    <guravage@caterpie.sen.cwi.nl>
 

	
 
	* simitembase.cpp: Removed NULL assignments to unused variables.
 
	* VirtualLeaf.cpp: Ditto.
 
	* apoplastitem.cpp: Ditto.
 
	* canvas.cpp: Ditto.
 
	* cell.cpp: Ditto.
 
	* cellbase.h: Ditto.
 
	* forwardeuler.cpp: Ditto.
 
	* mainbase.h: Ditto.
 
	* nodeitem.cpp: Ditto.
 
	* qcanvasarrow.h: Ditto.
 
	* simitembase.cpp: Ditto.
 

	
 

	
 
	* Makefile (clean): Add -f Makefile argument to each make invocation.
 

	
 
	* VirtualLeaf-install.nsi: New gpl license text.
 

	
 
	* VirtualLeaf.pro: Disabled console mode.
 

	
 
	* mesh.cpp (Clear): Added parentheses to qDebug statments.
 
	(TestIllegalWalls): Replaced qDebug().
 

	
 
	* canvas.cpp (mouseReleaseEvent): Replaced qDebug() with cerr since qDebug complains about *node_set.
 

	
 
	* wall.cpp (CorrectWall): Rplaced gDebug() with cerr in transform call and when printing *this.
 

	
 
2010-06-22    <guravage@caterpie.sen.cwi.nl>
 

	
 
	* Makefile (tutorials): Add tutorials target.
 

	
 
2010-06-21    <guravage@caterpie.sen.cwi.nl>
 

	
 
	* parameter.cpp: Added particular reassignment of datadir.
 

	
 
	* canvas.cpp (gpl): Added GPL3 License text. Display detail text only if the source text file exists.
 

	
 
2010-06-18    <guravage@caterpie.sen.cwi.nl>
 

	
 
	* canvas.cpp (gpl): Added gpl slot to display GPL license.
 

	
 
	* VirtualLeaf.pro: Changed default LIBXML2DIR, LIBICONVDIR and LIBZDIR to corresponding distribution lib directories.
 
	* libplugin.pro: Ditto.
 

	
 
	* Makefile (clean): add if stmt not to `touch` on windows.
 

	
 
2010-06-17    <guravage@caterpie.sen.cwi.nl>
 

	
 
	* VirtualLeaf.pro: Removed perl references.
 
	* libplugin.pro: Ditto.
 

	
 
2010-06-15    <guravage@caterpie.sen.cwi.nl>
 

	
 
	* VirtualLeaf.pro: Removed xmlwritecode.cpp from SOURCES list.
 

	
 
	* xmlwrite.cpp (XMLSave): Removed references to XMLWriteLeafSourceCode and XMLWriteReactionsCode.
 
	* xmlwrite.h (XMLIO): Ditto!
 

	
 
	* mesh.cpp (findNextBoundaryNode): Initialize Node *next_boundary_node = NULL;
 

	
 
	* xmlwrite.cpp (XMLReadSimtime): Removed unused variable cur
 
	(XMLReadWalls): viz_flux need not be declared twice; default value of 0.0.
 
	(XMLReadCells): Removed unused count variable.
 
	(XMLReadSimtime): Removed unused cur variable.
 
	(XMLRead): Removed unused v_str variable.
 

	
 
	* simitembase.cpp (userMove): Use assignment merely to obviate compilation warning.
 
	(SimItemBase) Ditto.
 

	
 
	* qcanvasarrow.h (QGraphicsLineItem): Use assignment merely to obviate compilation warning.
 

	
 
	* output.cpp (OpenWriteFile): Removed unused par variable.
 

	
 
	* nodeitem.cpp (paint): Use assignment merely to obviate compilation warning.
 

	
 
	* forwardeuler.cpp (odeint): Use assignment merely to obviate compilation warning.
 

	
 
	* cell.cpp (DivideOverGivenLine): Use assignment merely to obviate compilation warning.
 

	
 
	* canvas.cpp (FigureEditor): Use assignments merely to obviate compilation errors.
 
	(mousePressEvent): Removed unused item variable.
 

	
 
	* apoplastitem.cpp
 
	(ApoplastItem): Removed unused par variable.
 
	(OnClick): Use NULL assignment merely to obviate compilation warning.
 

	
 
	* mainbase.h (MainBase): Use assignment merely to obviate compilation warning.
 

	
 
	* cellbase.h (CellsStaticDatamembers): Use assignment merely to obviate compilation warning.
 

	
 

	
 
	* cell.cpp: Wrapped diagnostic output in QDEBUG blocks.
 
	* VirtualLeaf.cpp ditto.
 
	* canvas.cpp ditto.
 
	* cell.cpp ditto.
 
	* data_plot.cpp ditto.
 
	* forwardeuler.cpp ditto.
 
	* mesh.cpp ditto.
 
	* mesh.h
 
	* random.cpp ditto.
 
	* wall.cpp ditto.
 
	* wallbase.cpp ditto.
 
	* wallitem.cpp ditto.
 

	
 

	
 
2010-06-07    <guravage@caterpie.sen.cwi.nl>
 

	
 
	* VirtualLeaf.pro: Removed explicit perl invocation to regerenerate parameter files.
 
	* libplugin.pro: ditto.
 

	
 
2010-06-03    <guravage@caterpie.sen.cwi.nl>
 

	
 
	* pardialog.h: Added default versions of this automatically generated file.
 
	* pardialog.cpp: ditto.
 
	* parameter.h: ditto.
 
	* parameter.cpp: ditto.
 

	
 
	* VirtualLeaf.pro: delete/generate  parameter.{h,cpp}and pardialog.{h,cpp} only if perl is installed.
 
 	* libplugin.pro: dito.
 

	
 
	* Makefile: Added top-level Makefile
 

	
 
2010-05-10    <guravage@caterpie.sen.cwi.nl>
 

	
 
	* VirtualLeaf.pro: Added -fPIC option to QMAKE_CXXFLAGS.
 

	
src/Neighbor.cpp
Show inline comments
 
/*
 
 *
 
 *  This file is part of the Virtual Leaf.
 
 *
 
 *  The Virtual Leaf is free software: you can redistribute it and/or modify
 
 *  VirtualLeaf 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,
 
 *  VirtualLeaf 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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include "Neighbor.h"
 
#include "cell.h"
 
#include <string>
 

	
 
static const std::string _module_id("$Id$");
 

	
 
Neighbor::Neighbor(void):
 
  cell(NULL), nb1(NULL), nb2(NULL){}
 
  cell(0), nb1(0), nb2(0){}
 

	
 
Neighbor::Neighbor(Cell *c, Node *n1, Node *n2):
 
  cell(c), nb1(n1), nb2(n2){}
 

	
 
Neighbor::Neighbor(const Neighbor &src):
 
  cell(src.cell), nb1(src.nb1), nb2(src.nb2){} // copy constructor
 

	
 
bool Neighbor::CellEquals(int i) const { return cell->Index() == i; } 
 
bool Neighbor::Cmp(Neighbor &c) const { return cell->Index() < c.cell->Index(); } // Compare cell indices not pointers.
 
bool Neighbor::Eq(Neighbor &c) const { return cell->Index() == c.cell->Index(); }
 
Cell* Neighbor::getCell(void) const { return cell; } 
 

	
 
bool neighbor_cell_eq(const Neighbor &n1, const Neighbor &n2) {
 
  return (n1.getCell())->Index() == (n2.getCell())->Index(); // Compare cell indices not pointers.
 
}
 

	
 
/* finis */
 

	
src/Neighbor.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  This file is part of the Virtual Leaf.
 
 *
 
 *  The Virtual Leaf is free software: you can redistribute it and/or modify
 
 *  VirtualLeaf 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,
 
 *  VirtualLeaf 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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 

	
 
#ifndef _NEIGHBOR_H_
 
#define _NEIGHBOR_H_
 

	
 
#include <iostream>
 
#include <libxml/parser.h>
 
#include <libxml/tree.h>
 

	
 
using namespace std;
 

	
 
class Cell;
 
class Node;
 

	
 
class Neighbor {
 

	
 
 protected:
 
  // Proper accessors and mutators should obviate these friend classes!
 
  friend class Cell;
 
  friend class Mesh;
 
  friend class Node;
 
  friend class FigureEditor;
 

	
 
  Cell *cell;
 
  Node *nb1, *nb2;
 

	
 
 public:
 
  Neighbor(void);
 
  Neighbor(Cell*, Node*, Node*);
 
  Neighbor(const Neighbor&);
 

	
 
  bool CellEquals(int) const;
 
  bool Cmp(Neighbor&) const;
 
  bool Eq(Neighbor&) const;
 
  Cell* getCell(void) const;
 
  void XMLAdd(xmlNodePtr) const;
 

	
 
  ostream &print(ostream &os) const;
 
};
 

	
 
// Overload the << operator 
 
ostream &operator<<(ostream &os, const Neighbor &n);
 

	
 
// Realize that we're equating like pointers with object equivalence!
 
bool neighbor_cell_eq(const Neighbor &n1, const Neighbor &n2);
 

	
 
#endif
 

	
 
/* finis */
 

	
src/OptionFileDialog.cpp
Show inline comments
 
/*
 
 *
 
 *  This file is part of the Virtual Leaf.
 
 *
 
 *  The Virtual Leaf is free software: you can redistribute it and/or modify
 
 *  VirtualLeaf 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,
 
 *  VirtualLeaf 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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include <string>
 
#include "OptionFileDialog.h"
 
#include <QCheckBox>
 
#include <iostream>
 
using namespace  std; 
 

	
 
static const std::string _module_id("$Id$");
 

	
 
OptionFileDialog::OptionFileDialog(QWidget *parent, const char *name, bool modal) : Q3FileDialog(parent, name, modal)
 
{
 
  //cerr << "This is an OptionFileDialog\n";
 
  geometrycheck = new QCheckBox("geometry",this);
 
  geometrycheck -> setCheckState(Qt::Checked);
 

	
 
  parcheck = new QCheckBox("parameters", this);
 
  parcheck -> setCheckState(Qt::Checked);
 

	
 
  addToolButton(geometrycheck);
 
  addToolButton(parcheck);
 
};
 

	
 
OptionFileDialog::OptionFileDialog ( const QString & dirName, const QString & filter , 
 
				     QWidget * parent, const char * name , bool modal  ) :
 
  Q3FileDialog(dirName, filter, parent, name, modal) {
 

	
 
  cerr << "This is an OptionFileDialog\n";
 
};
 

	
 
/* finis */
src/OptionFileDialog.h
Show inline comments
 
/*
 
 *  $Id$
 
 *
 
 *  This file is part of the Virtual Leaf.
 
 *
 
 *  The Virtual Leaf is free software: you can redistribute it and/or modify
 
 *  VirtualLeaf 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,
 
 *  VirtualLeaf 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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#ifndef _OPTIONFILEDIALOG_H_
 
#define _OPTIONFILEDIALOG_H_
 

	
 
#include <Q3FileDialog>
 
#include <QCheckBox>
 

	
 
class OptionFileDialog : public Q3FileDialog {
 
  Q_OBJECT
 
 public:
 
  OptionFileDialog(QWidget *parent = 0, const char *name = 0, bool modal = false);
 
  OptionFileDialog ( const QString & dirName, const QString & filter = QString(), 
 
		     QWidget * parent = 0, const char * name = 0, bool modal = false );
 

	
 
  bool readGeometryP(void) const { return geometrycheck->checkState()==Qt::Checked; }
 
  bool readParametersP(void) const { return parcheck->checkState()==Qt::Checked; }
 

	
 
 private:
 
  QCheckBox *geometrycheck;	
 
  QCheckBox *parcheck;
 
};
 

	
 
#endif
 

	
 
/* finis */
src/UniqueMessage.cpp
Show inline comments
 
/*
 
 *
 
 *  This file is part of the Virtual Leaf.
 
 *
 
 *  The Virtual Leaf is free software: you can redistribute it and/or modify
 
 *  VirtualLeaf 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,
 
 *  VirtualLeaf 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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include <string>
 
#include <QMessageBox>
 
#include <QCheckBox>
 
#include <QPushButton>
 
#include <QBoxLayout>
 
#include "UniqueMessage.h"
 

	
 
#include <iostream>
 

	
 
static const std::string _module_id("$Id$");
 

	
 
using namespace std;
 
UniqueMessageBox::UniqueMessageBox ( /* Icon icon,*/ 
 
				    const QString & title, 
 
				    const QString & text, 
 
				    QWidget * parent ,
 
				    Qt::WindowFlags f ) : 
 
  QDialog(parent, f) {
 

	
 
  label = new QLabel(text);
 
  boxtext = text;
 

	
 
  show_again = new QCheckBox(tr("Do not show this message again"));
 
  okButton = new QPushButton(tr("Ok"));
 

	
 
  if (issued_messages.contains(boxtext) ) {
 

	
 
    cerr << "Saw message before\n";
 
    display = false;
 
  } else {
 
    display=true;
 
  }
 

	
 
  connect(okButton, SIGNAL(clicked()), this, SLOT(close()) );
 
  QHBoxLayout *hlayout = new QHBoxLayout;
 
  hlayout->addWidget(label);
 
  hlayout->addWidget(okButton);
 
  QVBoxLayout *layout = new QVBoxLayout;
 
  layout->addLayout(hlayout);
 
  layout->addWidget(show_again);
 
  setLayout(layout);
 
  setWindowTitle(title);
 
};
 

	
 
UniqueMessageBox::~UniqueMessageBox(void)  {
 

	
 
  if (show_again->checkState() == Qt::Checked ) {
 
    cerr << "Message won't be shown again\n";
 
    issued_messages << boxtext;
 
  }
 
}
 
int UniqueMessageBox::exec(void)  {
 

	
 
  if (display)
 
    return QDialog::exec();
 
  else {
 
    return 1;
 
  }
 
}
 

	
 
QStringList UniqueMessageBox::issued_messages;
 

	
 
/* finis */
src/UniqueMessage.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  This file is part of the Virtual Leaf.
 
 *
 
 *  The Virtual Leaf is free software: you can redistribute it and/or modify
 
 *  VirtualLeaf 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,
 
 *  VirtualLeaf 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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 

	
 
#ifndef _UNIQUEMESSAGE_H_
 
#define _UNIQUEMESSAGE_H_
 

	
 
#include <QDialog>
 
#include <QCheckBox>
 
#include <QStringList>
 
#include <QLabel>
 

	
 
class UniqueMessageBox : public QDialog {
 
  Q_OBJECT
 

	
 
 public:
 
  UniqueMessageBox ( /* Icon icon,*/ 
 
		    const QString & title, 
 
		    const QString & text, 
 
		    /* StandardButtons buttons = Ok, */
 
		    QWidget * parent = 0 , Qt::WindowFlags f = Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint );
 
  ~UniqueMessageBox();
 
  int exec(void);
 

	
 
 private:
 
  static QStringList issued_messages;
 
  bool display;
 
  QCheckBox *show_again;
 
  QPushButton *okButton;
 
  QLabel *label;
 
  QString boxtext;
 
};
 

	
 
#endif
 

	
 
/* finis */
src/VirtualLeaf.cpp
Show inline comments
 
/*
 
 *
 
 *  This file is part of the Virtual Leaf.
 
 *
 
 *  The Virtual Leaf is free software: you can redistribute it and/or modify
 
 *  VirtualLeaf 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,
 
 *  VirtualLeaf 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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include <string>
 
#include <fstream>
 
#include <sstream>
 
#include <cstring>
 
#include <functional> 
 
#include <getopt.h>
 
#include <cerrno>
 
#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 <qwidget.h>
 
#include <q3process.h>
 
#include <qapplication.h>
 
#include <QDesktopWidget>
 
#include <QGraphicsScene>
 
#include <QMessageBox>
 
//Added by qt3to4:
 
#include <QMouseEvent>
 

	
 
#include <unistd.h>
 
#include <q3textstream.h> 
 

	
 
#ifdef HAVE_QWT
 
#include "data_plot.h"
 
#endif
 
#include <QPalette>
 
#include <QBrush>
 
#include <QToolTip>
 
#include "simplugin.h"
 
#include <QPluginLoader>
 
#include <QDir>
 
#include "modelcatalogue.h"
 

	
 
static const std::string _module_id("$Id$");
 

	
 
extern Parameter par;
 

	
 
MainBase *main_window = 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<Node *>::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<double>( 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();
 
	  //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());
 
		QString info_string=QString("Cell %1, chemicals(%2): ").arg(c.Index()).arg(Cell::NChem());
 
		for (int i=0;i<Cell::NChem();i++) {
 
			info_string += QString("%1 ").arg(c.Chemical(i));
 
		}
 
		info_string += QString("\nArea is %1\n Circumference is %2\n Boundary type is %3").arg(c.Area()).arg(c.Circumference()).arg(c.BoundaryStr());
 
		
 
	  info_string += "\nNodes: " + 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) ) {
 
    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()) 
 
/*  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 << ".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());
 
    }
 
  }
 
 count++;
 
}
 

	
 

	
 

	
 
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	
 
      mesh.ReactDiffuse(par.rd_dt);
 
      t++;
 
      Plot(par.resize_stride);
 
    }
 
  } else {
 
    mesh.ReactDiffuse(par.rd_dt);
 
    Plot(par.resize_stride);
 
  }
 
  i++;
 
  return mesh.getTime();
 
}
 

	
 

	
 

	
 
/* Called if a cell is clicked */
 
void Cell::OnClick(QMouseEvent *e){}
 

	
 

	
 
/* 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;
 
    char *modelfile=0;
 

	
 
    while (1) {
 

	
 
      //int this_option_optind = optind ? optind : 1;
 
      int option_index = 0;
 
      static struct option long_options[] = {
 
	{"batch", no_argument, NULL, 'b'},
 
	{"leaffile", required_argument, NULL, 'l'},
 
	{"model", required_argument, NULL, 'm'} 
 
      };
 

	
 
      // short option 'p' creates trouble for non-commandline usage on MacOSX. Option -p changed to -P (capital)
 
      static char *short_options = "blm";
 
      c = getopt_long (argc, argv, "bl:m:",
 
		       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 'm':
 
	modelfile=strdup(optarg);
 
	if (!modelfile) {
 
	  throw("Out of memory");
 
	}
 
	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();
 
      }
 
      
 
      // show "About" window at start up
 
      ((Main *)main_window)->about();
 
    } else {
 
      main_window=new MainBase(canvas, mesh);
 
    }
 

	
 
    canvas.setSceneRect(QRectF());
 
    if (!batch) {
 
      QObject::connect( qApp, SIGNAL(lastWindowClosed()), qApp, SLOT(quit()) );
 
    }
 

	
 
    // Install model or read catalogue of models
 
    ModelCatalogue model_catalogue(&mesh, useGUI?(Main *)main_window:0,modelfile);
 
    if (useGUI)
 
      model_catalogue.PopulateModelMenu();
 
    model_catalogue.InstallFirstModel();
 

	
 
    if (leaffile) 
 
      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() <<endl;
 
      abort();
 
    } else {
 
      QString qmess(error_message.str().c_str());
 
      QMessageBox::critical(0, "I/O Error", qmess );
 
      abort();
 
    }
 
  }
 
}
 

	
 
/* finis */
src/VirtualLeaf.pro
Show inline comments
 
#
 
#  $Id$
 
#
 
#  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 <http://www.gnu.org/licenses/>.
 
#
 
#  Copyright 2010 Roeland Merks.
 
#
 

	
 
CONFIG += release
 
CONFIG -= debug
 
CONFIG += qt
 

	
 
QMAKE_CXXFLAGS += -fexceptions
 
QMAKE_CXXFLAGS += -Wall
 
QMAKE_CXXFLAGS_DEBUG += -g3
 
QMAKE_CXXFLAGS_DEBUG += -DQDEBUG
 

	
 
#REACTIONS = reactions_auxin_growth.h 
 
#REACTIONS = reactions_meinhardt.h
 
#REACTIONS = reactions_pce_growth.h
 
DEFINES += QTGRAPHICS
 
DEFINES += REACTIONS_HEADER=$${REACTIONS}
 
DEFINES += REACTIONS_HEADER_STRING=\"$${REACTIONS}\"
 
DEFINES += FLEMING
 

	
 
BINDIR = ../bin
 
DESTDIR = $$BINDIR
 
TARGET = VirtualLeaf
 
TEMPLATE = app
 
PARTMPL = $${TARGET}par.tmpl
 
MAINSRC = $${TARGET}.cpp
 
QT -= network sql xml
 
QT += qt3support
 

	
 
!win32 {
 
 GRAPHICS = qt #qwt
 
}
 

	
 
win32 {
 
 CONFIG -= console
 
 LIBXML2DIR = ..\lib\libxml2
 
 LIBICONVDIR = ..\lib\libiconv
 
 LIBZDIR = ..\lib\libz
 
 LIBXML2DIR = C:
 
 LIBICONVDIR = C:
 
 LIBZDIR = C:
 
 GRAPHICS = qt 
 
 RC_FILE = VirtualLeaf.rc
 
 QMAKE_CXXFLAGS += -DLIBXML_STATIC
 
# QMAKE_CXXFLAGS += -DLIBXML_STATIC
 
 QMAKE_CXXFLAGS += -I$${LIBXML2DIR}\include -I$${LIBICONVDIR}\include -I$${LIBZDIR}\include
 
 LIBS += -L$${LIBXML2DIR}\lib -lxml2 -L$${LIBICONVDIR}\lib -L$${LIBZDIR}\lib  -lz -lm -lwsock32 -liconv
 
}
 

	
 

	
 
macx:release {
 
 LIBS+= -dead_strip
 
}
 

	
 
unix {
 
 CC = /usr/bin/gcc 
 
 QWTDIR = /ufs/guravage/opt/qwt-5.2.1-svn
 
 QMAKE_LIBDIR += $$QWTDIR/lib 
 
 QMAKE_CXXFLAGS += -fPIC -I/usr/include/libxml2
 
 QMAKE_LFLAGS += -fPIC
 
 LIBS += -lxml2 -lz -lm 
 
}
 

	
 
# Input
 
HEADERS += \
 
 apoplastitem.h \
 
# apoplastitem.h \
 
 canvas.h \
 
 cellbase.h \
 
 cell.h \
 
 cellitem.h \
 
 forwardeuler.h \
 
 infobar.h \
 
 mainbase.h \
 
 mainbase.h \
 
 matrix.h \
 
 mesh.h \
 
 miscq.h \
 
 modelcatalogue.h \
 
 Neighbor.h \
 
 node.h \
 
 nodeitem.h \
 
 nodeset.h \
 
 OptionFileDialog.h \
 
 output.h \
 
 parameter.h \
 
 pardialog.h \
 
 parse.h \
 
 pi.h \
 
 qcanvasarrow.h \
 
 random.h \
 
 rungekutta.h \
 
 simitembase.h \
 
 simplugin.h \
 
 sqr.h \
 
 tiny.h \
 
 transporterdialog.h \
 
 UniqueMessage.h \
 
 vector.h \
 
 wallbase.h \
 
 wall.h \
 
 wallitem.h \
 
 warning.h \
 
 xmlwrite.h \
 
 $${PARTMPL}
 

	
 
SOURCES += \
 
 apoplastitem.cpp \
 
# apoplastitem.cpp \
 
 canvas.cpp \
 
 cellbase.cpp \
 
 cell.cpp \
 
 cellitem.cpp \
 
 forwardeuler.cpp \
 
 mainbase.cpp \
 
 matrix.cpp \
 
 mesh.cpp \
 
 miscq.cpp \
 
 modelcatalogue.cpp \
 
 Neighbor.cpp \
 
 node.cpp \
 
 nodeitem.cpp \
 
 nodeset.cpp \
 
 OptionFileDialog.cpp \
 
 output.cpp \
 
 parameter.cpp \
 
 pardialog.cpp \
 
 parse.cpp \
 
 random.cpp \
 
 rungekutta.cpp \
 
 simitembase.cpp \
 
 transporterdialog.cpp \
 
 UniqueMessage.cpp \
 
 vector.cpp \
 
 wallbase.cpp \
 
 wall.cpp \
 
 wallitem.cpp \
 
 warning.cpp \
 
 xmlwrite.cpp \
 
 $$MAINSRC
 

	
 
contains( TARGET, leaf_fleming ) {
 
 DEFINES += FLEMING	
 
}
 

	
 
contains(GRAPHICS, qwt) {
 
 #macx:LIBS += -L$$QWTDIR/lib -lqwt
 
 #win32:LIBS += -L$$QWTDIR/lib -lqwt5
 
 #LIBS += -L$$QWTDIR/lib -lqwt
 
 INCLUDEPATH += $$QWTDIR/include
 
 DEFINES += HAVE_QWT
 
 HEADERS += data_plot.h
 
 SOURCES += data_plot.cpp
 
}
 

	
 
contains( GRAPHICS, qt ) {
 
 message( "Building Qt executable" )
 
 QMAKE_CXXFLAGS += -DQTGRAPHICS # -fpermissive
 
}
 

	
 
contains( GRAPHICS, xfig ) {
 
 message("Building Xfig executable (background runnable).")
 
 QMAKE_CXXFLAGS += -DXFIGGRAPHICS
 
}
 

	
 
contains( GRAPHICS, x11 ) {
 
 !unix {
 
  error("X11 graphics only available on Unix systems.")
 
 }
 
 message("Building X11 executable")
 
 SOURCES += x11graph.cpp
 
 HEADERS += x11graph.h
 
 QMAKE_CXXFLAGS += -DX11GRAPHICS
 
 CONFIG -= qt
 
 CONFIG += x11
 
 unix:LIBS += -lpng
 
}
 

	
 
#contains( GRAPHICS, qwt ) {
 
# 	QMAKE_POST_LINK = "install_name_tool -change libqwt.5.dylib $$QWTDIR/lib/libqwt.dylib $${TARGET}.app/Contents/MacOS/$${TARGET}; \
 
#}
 

	
 
# MACOSX packaging
 
macx {
 
ICON = leaficon.icns
 
QMAKE_POST_LINK = "\
 
	#install_name_tool -change libqwt.5.dylib $$QWTDIR/lib/libqwt.dylib $${TARGET}.app/Contents/MacOS/$${TARGET}; \
 
	cp leaficon.icns $${DESTDIR}/$${TARGET}.app; \
 
	mkdir $${DESTDIR}/$${TARGET}.app/Contents/Frameworks; \
 
	cp -R /Library/Frameworks/QtCore.framework $${DESTDIR}/$${TARGET}.app/Contents/Frameworks; \
 
	cp -R /Library/Frameworks/QtGui.framework $${DESTDIR}/$${TARGET}.app/Contents/Frameworks; \
 
	cp -R /Library/Frameworks/Qt3Support.framework $${DESTDIR}/$${TARGET}.app/Contents/Frameworks; \
 
	#cp /usr/local/qwt/lib/libqwt.dylib $${DESTDIR}/$${TARGET}.app/Contents/Frameworks; \
 
	#install_name_tool -id @executable_path/../Frameworks/libqwt.dylib $${DESTDIR}/$${TARGET}.app/Contents/Frameworks/libqwt.dylib; \
 
	install_name_tool -change /usr/local/qwt/lib/libqwt.dylib @executable_path/../Frameworks/libqwt.dylib $${DESTDIR}/$${TARGET}.app/Contents/MacOS/$${TARGET};\
 
	install_name_tool -id @executable_path/../Frameworks/QtCore.framework/Versions/Current/QtCore $${DESTDIR}/$${TARGET}.app/Contents/Frameworks/QtCore.framework/Versions/4.0/QtCore; \
 
	install_name_tool -id @executable_path/../Frameworks/QtGui.framework/Versions/Current/QtGui $${DESTDIR}/$${TARGET}.app/Contents/Frameworks/QtGui.framework/Versions/4.0/QtGui; \
 
	install_name_tool -id @executable_path/../Frameworks/Qt3Support.framework/Versions/Current/Qt3Support $${DESTDIR}/$${TARGET}.app/Contents/Frameworks/Qt3Support.framework/Versions/4.0/Qt3Support; \
 
	install_name_tool -change Frameworks/QtCore.framework/Versions/Current/QtCore @executable_path/../Frameworks/QtCore.framework/Versions/4.0/QtCore $${DESTDIR}/$${TARGET}.app/Contents/MacOS/$${TARGET}; \
 
	install_name_tool -change Frameworks/QtGui.framework/Versions/Current/QtGui @executable_path/../Frameworks/QtGui.framework/Versions/4.0/QtGui $${DESTDIR}/$${TARGET}.app/Contents/MacOS/$${TARGET}; \
 
	install_name_tool -change Frameworks/Qt3Support.framework/Versions/Current/Qt3Support @executable_path/../Frameworks/Qt3Support.framework/Versions/4.0/Qt3Support $${DESTDIR}/$${TARGET}.app/Contents/MacOS/$${TARGET}; \
 
	install_name_tool -change Frameworks/QtCore.framework/Versions/Current/QtCore @executable_path/../Frameworks/QtCore.framework/Versions/4.0/QtCore $${DESTDIR}/$${TARGET}.app/Contents/Frameworks/Qt3Support.framework/Versions/4.0/Qt3Support; \
 
	install_name_tool -change Frameworks/QtGui.framework/Versions/Current/QtGui @executable_path/../Frameworks/QtGui.framework/Versions/4.0/QtGui $${DESTDIR}/$${TARGET}.app/Contents/Frameworks/Qt3Support.framework/Versions/4.0/Qt3Support; \
 
	install_name_tool -change Frameworks/QtCore.framework/Versions/Current/QtCore @executable_path/../Frameworks/QtCore.framework/Versions/4.0/QtCore $${DESTDIR}/$${TARGET}.app/Contents/Frameworks/Qt3Support.framework/Versions/4.0/Qt3Support; "
 
}
 

	
 
# finis
src/build_models/plugin_auxingrowth.pro
Show inline comments
 
#
 
# $Id$
 
#
 
#  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 <http://www.gnu.org/licenses/>.
 
#
 
#  Copyright 2010 Roeland Merks.
 
#
 

	
 
CONFIG += release
 
CONFIG -= debug
 
CONFIG += plugin
 

	
 
BINDIR = ../../bin
 
LIBDIR = ../../lib
 
DEFINES = QTGRAPHICS # VLEAFPLUGIN
 
DESTDIR = $${BINDIR}/models
 
TARGET = auxingrowth
 
HEADERS = ../simplugin.h $${TARGET}plugin.h  
 
QMAKE_CXXFLAGS += -fexceptions -I..
 
QMAKE_CXXFLAGS_DEBUG += -g3
 
QMAKE_CXXFLAGS_DEBUG += -DQDEBUG
 

	
 
QT += qt3support
 
SOURCES = $${TARGET}plugin.cpp
 
TEMPLATE = lib 
 

	
 
unix {
 
 LIBS += -L$${LIBDIR} -lvleaf
 
 QMAKE_CXXFLAGS += -fPIC -I/usr/include/libxml2
 
 QMAKE_LFLAGS += -fPIC
 
}
 

	
 
win32 {
 
 LIBXML2DIR = ..\..\lib\libxml2
 
 LIBICONVDIR = ..\..\lib\libiconv
 
 LIBZDIR = ..\..\lib\libz
 
 LIBXML2DIR = $${LIBDIR}\lib\libxml2
 
 LIBICONVDIR = $${LIBDIR}\lib\libiconv
 
 LIBZDIR = $${LIBDIR}\lib\libz
 
 LIBS += -L$${LIBDIR} -Llib -lvleaf
 
 QMAKE_CXXFLAGS += -DLIBXML_STATIC
 
 QMAKE_CXXFLAGS += -I$${LIBXML2DIR}\include -I$${LIBICONVDIR}\include -I$${LIBZDIR}\include
 
}
 

	
 
# finis
src/build_models/plugin_meinhardt.pro
Show inline comments
 
#
 
# $Id$
 
#
 
#  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 <http://www.gnu.org/licenses/>.
 
#
 
#  Copyright 2010 Roeland Merks.
 
#
 

	
 
CONFIG += release
 
CONFIG -= debug
 
CONFIG += plugin
 

	
 
BINDIR = ../../bin
 
LIBDIR = ../../lib
 
DEFINES = QTGRAPHICS # VLEAFPLUGIN
 
DESTDIR = $${BINDIR}/models
 
TARGET = meinhardt
 
HEADERS = ../simplugin.h $${TARGET}plugin.h  
 
QMAKE_CXXFLAGS += -fexceptions -I..
 
QMAKE_CXXFLAGS_DEBUG += -g3
 
QMAKE_CXXFLAGS_DEBUG += -DQDEBUG
 

	
 
QT += qt3support
 
SOURCES = $${TARGET}plugin.cpp
 
TEMPLATE = lib 
 

	
 
unix {
 
 LIBS += -L$${LIBDIR} -lvleaf
 
 QMAKE_CXXFLAGS += -fPIC -I/usr/include/libxml2
 
 QMAKE_LFLAGS += -fPIC
 
}
 

	
 
win32 {
 
 LIBXML2DIR = ..\..\lib\libxml2
 
 LIBICONVDIR = ..\..\lib\libiconv
 
 LIBZDIR = ..\..\lib\libz
 
 LIBXML2DIR = $${LIBDIR}\lib\libxml2
 
 LIBICONVDIR = $${LIBDIR}\lib\libiconv
 
 LIBZDIR = $${LIBDIR}\lib\libz
 
 LIBS += -L$${LIBDIR} -Llib -lvleaf
 
 QMAKE_CXXFLAGS += -DLIBXML_STATIC
 
 QMAKE_CXXFLAGS += -I$${LIBXML2DIR}\include -I$${LIBICONVDIR}\include -I$${LIBZDIR}\include
 
}
 

	
 
# finis
 

	
src/build_models/plugin_test.pro
Show inline comments
 
#
 
# $Id$
 
#
 
#  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 <http://www.gnu.org/licenses/>.
 
#
 
#  Copyright 2010 Roeland Merks.
 
#
 

	
 
CONFIG += release
 
CONFIG -= debug
 
CONFIG += plugin
 

	
 
BINDIR = ../../bin
 
LIBDIR = ../../lib
 
DEFINES = QTGRAPHICS # VLEAFPLUGIN
 
DESTDIR = $${BINDIR}/models
 
TARGET = test
 
HEADERS = ../simplugin.h $${TARGET}plugin.h  
 
QMAKE_CXXFLAGS += -fexceptions -I..
 
QMAKE_CXXFLAGS_DEBUG += -g3
 
QMAKE_CXXFLAGS_DEBUG += -DQDEBUG
 

	
 
QT += qt3support
 
SOURCES = $${TARGET}plugin.cpp
 
TEMPLATE = lib 
 

	
 
unix {
 
 LIBS += -L$${LIBDIR} -lvleaf
 
 QMAKE_CXXFLAGS += -fPIC -I/usr/include/libxml2
 
 QMAKE_LFLAGS += -fPIC
 
}
 

	
 
win32 {
 
 LIBXML2DIR = ..\..\lib\libxml2
 
 LIBICONVDIR = ..\..\lib\libiconv
 
 LIBZDIR = ..\..\lib\libz
 
 LIBXML2DIR = $${LIBDIR}\lib\libxml2
 
 LIBICONVDIR = $${LIBDIR}\lib\libiconv
 
 LIBZDIR = $${LIBDIR}\lib\libz
 
 LIBS += -L$${LIBDIR} -Llib -lvleaf
 
 QMAKE_CXXFLAGS += -DLIBXML_STATIC
 
 QMAKE_CXXFLAGS += -I$${LIBXML2DIR}\include -I$${LIBICONVDIR}\include -I$${LIBZDIR}\include
 

	
 
}
 

	
 
# finis
src/canvas.cpp
Show inline comments
 
/*
 
 *
 
 *  This file is part of the Virtual Leaf.
 
 *
 
 *  The Virtual Leaf is free software: you can redistribute it and/or modify
 
 *  VirtualLeaf 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,
 
 *  VirtualLeaf 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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include <string>
 
#include <fstream>
 
#include <streambuf>
 
#include <QGraphicsScene>
 
#include <QGraphicsView>
 
#include <qdatetime.h>
 
#include <q3mainwindow.h>
 
#include <qstatusbar.h>
 
#include <qmessagebox.h>
 
#include <qmenubar.h>
 
#include <qapplication.h>
 
#include <qpainter.h>
 
#include <qprinter.h>
 
#include <qlabel.h>
 
#include <qimage.h>
 
#include <q3progressdialog.h>
 
#include <qtimer.h>
 
#include <qslider.h>
 
#include <qpixmap.h>
 
#include <qfile.h>
 
#include <qdir.h>
 
#include <q3filedialog.h>
 
#include <QGraphicsItem>
 
#include <QList>
 
#include <QDir>
 

	
 
#include <QDebug>
 

	
 
#include <set>
 

	
 
//Added by qt3to4:
 
#include <Q3ValueList>
 
#include <Q3PopupMenu>
 
#include <QMouseEvent>
 
#include <typeinfo>
 
#include <cstring>
 
#include <q3process.h>
 
#include <qlayout.h>
 
#include <qspinbox.h>
 
#include <fstream>
 
#include <sstream>
 
#include "pardialog.h"
 
#include "parameter.h"
 
#include "canvas.h"
 
#include "node.h"
 
#include "nodeset.h"
 
#include "nodeitem.h"
 
#include "cellitem.h"
 
#include "wallitem.h"
 
#include "mesh.h"
 
#include "xmlwrite.h"
 
#include "miscq.h"
 
#include "OptionFileDialog.h"
 
#include <cstdlib>
 
#include <cstdio>
 
#include "modelcatalogue.h"
 

	
 
#include <algorithm>
 

	
 
// Include VIB and PSB logos
 
#include "psb.xpm"
 
#include "cwi.xpm"
 

	
 
static const std::string _module_id("$Id$");
 

	
 
// We use a global variable to save memory - all the brushes and pens in
 
// the mesh are shared.
 

	
 
#define QUOTE_ME(s) QUOTE_ME_2NDLEV(s)
 
#define QUOTE_ME_2NDLEV(s) #s
 

	
 
static QColor dark_red("darkRed");
 

	
 

	
 
static const int imageRTTI = 984376;
 
extern Parameter par;
 
const QString Main::caption("Virtual leaf");
 
const QString Main::caption_with_file("Virtual leaf: %1");
 

	
 
FigureEditor::FigureEditor(
 
			   QGraphicsScene& c, Mesh &m, QWidget* parent,
 
			   const char* name, Qt::WindowFlags f) :
 
  QGraphicsView(&c,parent), mesh(m)
 
{
 
  intersection_line = 0;
 
  //angle_line = 0;
 
  setInteractive(true);
 
  moving = 0;  
 
  rotation_mode = false;
 
}
 

	
 

	
 
void FigureEditor::clear()
 
{
 
  QList<QGraphicsItem *> list = scene()->items();
 
  QList<QGraphicsItem *>::Iterator it = list.begin();
 
  for (; it != list.end(); ++it) {
 
    delete *it;
 
  }
 
}
 

	
 
void FigureEditor::wheelEvent(QWheelEvent *event)
 
{
 
  scaleView(pow((double)2, -event->delta() / 240.0));
 
}
 

	
 

	
 
void FigureEditor::scaleView (qreal scaleFactor)
 
{
 
  qreal factor = matrix().scale(scaleFactor, scaleFactor).mapRect(QRectF(0, 0, 1, 1)). width();
 
  if (factor < 0.07 || factor > 100) return;
 
  scale (scaleFactor, scaleFactor);
 
}
 

	
 
void FigureEditor::Save(const char *fname, const char *format, int sizex, int sizey)
 
{
 

	
 
  QImage *image = new QImage(sizex, sizey, QImage::Format_RGB32);
 
  image->fill(QColor(Qt::white).rgb());
 
  QPainter *painter=new QPainter(image);
 

	
 
  render(painter);
 

	
 
  image->save(QString(fname),format);
 
  delete painter;
 
  delete image;
 
}
 

	
 
void FigureEditor::mousePressEvent(QMouseEvent* e)
 
{
 
  static QList<Node*> selected;
 
  emit MousePressed();
 

	
 
  //QPointF p = matrix().inverted().map(e->pos());
 
  QPointF p = mapToScene(e->pos());
 

	
 
#ifdef QDEBUG  
 
  qDebug() << endl << "MousePressEvent location: (" << p.x() << "," << p.y() << ")." << endl;
 
  qDebug() << "Magnification:  " << Cell::Magnification() << endl;
 
  qDebug() << "Offsets:  " << Cell::Offset() << endl;
 
#endif
 

	
 

	
 
  QList<QGraphicsItem *> l=scene()->items(p);
 

	
 
#ifdef QDEBUG  
 
  qDebug() << "MousePressEvents, items: " << l.size() << endl;
 
  qDebug() << "Mouse button modifier: " << e->modifiers() << endl;
 
#endif
 

	
 
  if (e->button()==Qt::RightButton || l.size()==0) {
 

	
 
    //cerr << "Drawing an intersection line from " << p.x() << ", " << p.y() << endl;
 
    intersection_line = new QGraphicsLineItem( 0, scene() );
 
    intersection_line->setPen( QPen( QColor("red"), 3, Qt::DashLine ) );
 
    intersection_line->setLine( QLineF(p,p) );
 
    intersection_line->setZValue( 100 );
 
    intersection_line->show();
 
  }
 

	
 
  for (QList<QGraphicsItem *>::Iterator it=l.begin(); it!=l.end(); ++it) {
 
#ifdef QDEBUG
 
    qDebug() << typeid(**it).name() << endl;
 
#endif
 

	
 
    if ( !strcmp(typeid(**it).name(),"8NodeItem")) {
 

	
 
      stringstream data_strstream;
 
      data_strstream << (dynamic_cast<NodeItem*>(*it))->getNode();
 
      dynamic_cast<Main *>(parent())->UserMessage(QString(data_strstream.str().c_str()));
 

	
 
      (dynamic_cast<NodeItem*>(*it))->OnClick(e->button());
 
    }
 
    else 
 
      if ( !strcmp(typeid(**it).name(),"8CellItem") ) {
 

	
 
	Cell &c=((dynamic_cast<CellItem *>(*it))->getCell());      
 
	// OnClick to be defined in end-user code
 
	c.OnClick(e);
 
      } else {
 
	if ( !strcmp(typeid(**it).name(),"8WallItem") ) {
 
	  (dynamic_cast<WallItem *>(*it))->OnClick(e);
 
	} 
 
      }
 
  }
 

	
 
  FullRedraw();
 
  moving = 0;
 
}
 

	
 
void FigureEditor::mouseMoveEvent(QMouseEvent* e)
 
{
 

	
 
  // User chooses "rotation mode" and we can rotate the object around its center of mass
 
  if (dynamic_cast<Main *>(parent())->RotationModeP()) {
 

	
 
    QPointF p = mapToScene(e->pos());
 
    p.setX(p.x() / Cell::Magnification());
 
    p.setY(p.y() / Cell::Magnification());
 

	
 

	
 
    // get object's center of mass
 
    QPointF rotation_midpoint = mesh.Centroid()*Cell::Factor() - Cell::Offset();
 

	
 

	
 
    // calculate rotation angle
 
    double dy = (rotation_midpoint.y() - p.y());
 
    double dx = (rotation_midpoint.x() - p.x());
 
    double new_rot_angle = atan2(dx, dy);
 
    double d_alpha = new_rot_angle - rot_angle;
 
    rot_angle = new_rot_angle;
 

	
 
    mesh.Rotate(d_alpha, ( Vector(rotation_midpoint) + Cell::Offset() ) / Cell::Factor() );
 

	
 
    dynamic_cast<Main *>(parent())->Plot(0);
 
    FullRedraw();
 
    return;
 
  }
 
 
 
  
 
  if ( moving ) {
 

	
 
    QPointF p = mapToScene(e->pos());
 
    moving->userMove(p.x() - moving_start.x(),
 
		     p.y() - moving_start.y());
 
    moving_start = p;
 
    scene()->update();
 

	
 
  }
 

	
 
  //cerr << "event";
 

	
 
  // keep track of intersection line to interactively cut a growing leaf
 

	
 
  if ( intersection_line ) {
 

	
 
    QPointF sp = intersection_line -> line().p1(); // startpoint
 
    QPointF ep = mapToScene(e->pos()); // endpoint
 
    intersection_line -> setLine( QLineF(sp, ep) ); 
 
    scene()->update();
 
    // Need this for Mac
 
    FullRedraw();
 
  }
 
}
 

	
 
//void FigureEditor::contentsMouseReleaseEvent(QMouseEvent* e)
 
void FigureEditor::mouseReleaseEvent(QMouseEvent* e)
 
{
 

	
 
  emit MouseReleased();
 
  // intersection line for leaf was finished now.
 

	
 
  if (e->button()==Qt::LeftButton) { 
 
    if (intersection_line ) {
 
#ifdef QDEBUG
 
      qDebug() << "Trying to cut leaf" << endl;
 
#endif
 
      QPointF sp = intersection_line -> line().p1(); // startpoint
 
      QPointF ep = mapToScene(e->pos());
 

	
 
      intersection_line -> setLine( QLineF(sp, ep) ); 
 
      intersection_line -> show();
 

	
 
      vector <CellItem *> intersected_cells = getIntersectedCells();
 

	
 
      // no cells selected, do nothing
 
      if (intersected_cells.size()==0) {
 
#ifdef QDEBUG
 
	qDebug() << "No cells detected :-(" << endl;
 
#endif
 
	return;
 
      }
 

	
 

	
 
      Vector startpoint = Vector(sp.x(), sp.y()) / Cell::Factor() - Cell::Offset();
 
      Vector endpoint = Vector(ep.x(), ep.y()) / Cell::Factor() - Cell::Offset();
 

	
 
      NodeSet *node_set = new NodeSet;
 

	
 
      for (vector<CellItem *>::iterator it = intersected_cells.begin(); it != intersected_cells.end(); it++) {
 
	(*it)->setBrush(QBrush("purple"));
 
	
 
	Cell &c=(*it)->getCell();
 

	
 
	// sometimes the cell hasn't properly divided yet before the
 
	// next division is called?  so check for it?  let's find a way
 
	// to do this later. Note that this functionality currently
 
	// might result in a segmentation fault for users who are
 
	// quickly dragging and releasing division lines...
 
	scene()->update();
 

	
 
#ifdef QDEBUG
 
	qDebug() << "Dividing Cell " << c.Index() << endl;
 
#endif
 

	
 
	c.DivideOverGivenLine( startpoint, endpoint, true, node_set);
 
      }
 

	
 
      node_set->CleanUp();
 
      mesh.AddNodeSet(node_set);
 

	
 
#ifdef QDEBUG
 
      qDebug() << "Done DivideOverGivenLine" << endl;
 
#endif
 

	
 
      mesh.TestIllegalWalls();
 
      // Do the actual cutting and removing
 
      if (intersected_cells.size()) {
 
	mesh.CutAwayBelowLine( startpoint, endpoint ); 
 

	
 
	// Correct flags of nodeset
 
	for (NodeSet::iterator i = node_set->begin(); i != node_set->end(); i++) {
 
	  (*i)->SetSAM();
 
	  (*i)->SetBoundary();
 
	}
 

	
 
	// Make cells attached to nodeset part of the boundary
 
	// This is a temporary solution for the following:
 
	//   If a cell attached to a NodeSet divides (with a division plane intersecting the node set), 
 
	//   we must insert a new node into the node set.
 
	// For now, we add a layer of "virtual cells" inbetween. 
 
	list<Cell *> cells_attached_to_nodeset = node_set->getCells();
 
	for ( list<Cell *>::iterator c = cells_attached_to_nodeset.begin(); c != cells_attached_to_nodeset.end(); c++) {
 
	  (*c)->SetBoundary(Cell::SAM);
 
	}
 

	
 

	
 

	
 
#ifdef QDEBUG
 
	qDebug() << "Done CutAwayBelowLine" << endl;
 
#endif
 
	mesh.TestIllegalWalls();
 
	mesh.RepairBoundaryPolygon();
 
#ifdef QDEBUG
 
	qDebug() << "Done RepairBoundaryPolygon" << endl;
 
#endif
 
	mesh.TestIllegalWalls();
 
	mesh.CleanUpWalls();
 
#ifdef QDEBUG
 
	qDebug() << "Done CleanUpWalls" << endl;
 
#endif
 
	mesh.TestIllegalWalls();
 
      }
 

	
 
      dynamic_cast<Main *>(parent())->Plot();
 

	
 
#ifdef QDEBUG
 
      cerr << "NodeSet of cutting line: " << *node_set << endl;
 
#endif
 
    }
 
  } else 
 
    if (e->button()==Qt::RightButton) {
 

	
 
      if (intersection_line /* && !angle_line*/) {
 

	
 
	QPointF p = mapToScene(e->pos());
 
	QPointF sp = intersection_line->line().p1();
 

	
 
	viewport()->setMouseTracking( TRUE );
 
      } 
 
    }
 
}
 

	
 

	
 
// returns a vector of pointer to cells colliding with intersection line
 
vector <CellItem *> FigureEditor::getIntersectedCells(void)
 
{ 
 
  vector <CellItem *> colliding_cells;
 

	
 
  QList<QGraphicsItem *> l = intersection_line->collidingItems( );
 

	
 
#ifdef QDEBUG
 
  qDebug() <<  "l.size() = " << l.size() << endl;
 
#endif
 

	
 
  for (QList<QGraphicsItem *>::Iterator it=l.begin(); it!=l.end(); ++it) {
 

	
 
#ifdef QDEBUG
 
    qDebug() << typeid(**it).name() << endl;
 
#endif
 

	
 
    if ( !strcmp(typeid(**it).name(),"8CellItem") ) {
 
      colliding_cells.push_back(dynamic_cast<CellItem *>(*it));
 
    }
 
  }
 

	
 
  delete intersection_line;
 
  intersection_line = 0;
 
  return colliding_cells;
 
}
 

	
 
void FigureEditor::FullRedraw(void)
 
{
 
  QList<QRectF> rl;
 
  rl << sceneRect();
 
  updateScene(rl);   
 
}
 

	
 

	
 
NodeItem *FigureEditor::selectedNodeItem(QList<QGraphicsItem *> graphicItems) const
 
{
 
  NodeItem *nodeItem = 0;
 
  // graphicItems is a list of the QgraphicItems under the mouse click event 
 
  QList<QGraphicsItem *>::Iterator it = graphicItems.begin();
 
  for (; it != graphicItems.end(); ++it) {
 
    if ( !strcmp(typeid(**it).name(),"8NodeItem")) {
 
      // the object under the mouse click is a Nodeitem
 
      nodeItem = dynamic_cast<NodeItem *>(*it);
 
      // indicate we've selected it
 
      nodeItem->setBrush(dark_red);
 
      break;
 
    }
 
  }
 
  return nodeItem;
 
}
 

	
 

	
 
void FigureEditor::insertNode(QPointF p)
 
{
 
  Node *node = new Node(p.x(), p.y(), 0);
 
  mesh.AddNode(node);
 
  scene()->clearSelection();
 
  dynamic_cast<Main *>(parent())->Plot();
 
  FullRedraw();
 
#ifdef QDEBUG  
 
  qDebug() << "Node: " << p << endl;
 
#endif
 
}
 

	
 
static uint mainCount = 0;
 

	
 
Main::Main(QGraphicsScene& c, Mesh &m, QWidget* parent, const char* name, Qt::WindowFlags f) :
 
  Q3MainWindow(parent,name,f),
 
  MainBase(c,m),
 
  mesh(m)
 
{
 
  editor = new FigureEditor(canvas,mesh, this);
 

	
 
#ifdef QDEBUG
 
  qDebug() << "Interactive = " << editor->isEnabled();
 
#endif
 

	
 
  working_dir = 0;
 
  QObject::connect( editor, SIGNAL(MousePressed()), this, SLOT(PauseIfRunning()));
 
  QObject::connect( editor, SIGNAL(MouseReleased()), this, SLOT(ContIfRunning()));
 
  QMenuBar* menu = menuBar();
 

	
 
  Q3PopupMenu* file = new Q3PopupMenu( menu );
 

	
 
  file->insertItem("&Read leaf", this, SLOT(readStateXML()));
 
  file->insertItem("&Save leaf", this, SLOT(saveStateXML()));
 
  file->insertItem("Snapshot", this, SLOT(snapshot()), Qt::CTRL+Qt::SHIFT+Qt::Key_S);
 

	
 
  file->insertSeparator();
 
  file->insertItem("Read next leaf", this, SLOT(readNextStateXML()), Qt::Key_PageDown);
 
  file->insertItem("Read previous leaf", this, SLOT(readPrevStateXML()), Qt::Key_PageUp);
 
  file->insertItem("Read last leaf", this, SLOT(readLastStateXML()), Qt::Key_End);
 
  file->insertItem("Read first leaf", this, SLOT(readFirstStateXML()), Qt::Key_Home);
 

	
 
  file->insertSeparator();
 
  file->insertItem("&Print...", this, SLOT(print()), Qt::CTRL+Qt::Key_P);
 
  file->insertSeparator();
 
  file->insertItem("E&xit", qApp, SLOT(quit()), Qt::CTRL+Qt::Key_Q);
 
  menu->insertItem("&File", file);
 

	
 
  Q3PopupMenu* edit = new Q3PopupMenu( menu );
 
  edit->insertItem("Reset Chemicals and Transporters", this, SLOT( CleanMesh()), Qt::CTRL+Qt::Key_R );
 
  edit->insertItem("Reset Chemicals", this, SLOT( CleanMeshChemicals()) );
 
  edit->insertItem("Reset Transporters", this, SLOT( CleanMeshTransporters()) );
 
  edit->insertItem("Randomize PIN1 Transporters", this, SLOT( RandomizeMesh()) );
 
  edit->insertItem("Cut away SAM", this, SLOT( CutSAM() ));
 
  menu->insertItem("&Edit", edit);
 

	
 
  run = new Q3PopupMenu( menu );
 
  running = false;
 
  paused_id = run->insertItem("&Simulation paused", this, SLOT(togglePaused()), Qt::Key_S);
 
  run->setItemChecked(paused_id, FALSE);
 

	
 
  menu->insertItem("&Run", run);
 

	
 
  view = new Q3PopupMenu( menu );
 
  view->insertItem("&Zoom in", this, SLOT(zoomIn()), Qt::CTRL+Qt::Key_Equal);
 
  view->insertItem("Zoom &out", this, SLOT(zoomOut()), Qt::CTRL+Qt::Key_Minus);
 
  view->insertSeparator();
 
  com_id = view->insertItem("Show cell &centers", this, SLOT(toggleShowCellCenters()));
 
  view->setItemChecked(com_id, FALSE);
 

	
 
  mesh_id = view->insertItem("Show &nodes", this, SLOT(toggleShowNodes()), Qt::CTRL+Qt::SHIFT+Qt::Key_N);
 
  view->setItemChecked(mesh_id, TRUE);
 
  node_number_id = view->insertItem("Show node numbers", this, SLOT(toggleNodeNumbers()), Qt::CTRL+Qt::SHIFT+Qt::Key_M);
 
  view->setItemChecked(node_number_id, FALSE);
 
  cell_number_id = view->insertItem("Show cell numbers", this, SLOT(toggleCellNumbers()));
 
  view->setItemChecked(cell_number_id, FALSE);
 
  hide_cells_id = view->insertItem("Hide cells", this, SLOT(toggleHideCells()));
 
  view->setItemChecked(hide_cells_id, FALSE);
 
  border_id = view->insertItem("Show &border cells", this, SLOT(toggleShowBorderCells()));
 
  view->setItemChecked(border_id, FALSE);
 
  cell_axes_id = view->insertItem("Show cell &axes", this, SLOT(toggleCellAxes()));
 
  cell_strain_id = view->insertItem("Show cell &strain", this, SLOT(toggleCellStrain()));
 
  view->setItemChecked(cell_axes_id, FALSE);
 
  fluxes_id = view->insertItem("Show &fluxes", this, SLOT(toggleShowFluxes()));
 
  view->setItemChecked(fluxes_id, FALSE);
 
  cell_walls_id = view->insertItem("Show transporters", this, SLOT(toggleShowWalls()));
 
  view->setItemChecked(cell_walls_id, FALSE);
 
  apoplasts_id = view->insertItem("Show apoplasts", this, SLOT(toggleShowApoplasts()));
 
  view->setItemChecked(apoplasts_id, FALSE);
 
 // apoplasts_id = view->insertItem("Show apoplasts", this, SLOT(toggleShowApoplasts()));
 
 // view->setItemChecked(apoplasts_id, FALSE);
 
  view->insertSeparator();
 
  only_boundary_id = view->insertItem("Show only leaf &boundary", this, SLOT(toggleLeafBoundary()));
 
  view->insertSeparator();
 
  movie_frames_id = view->insertItem("Start saving movie &frames", this, SLOT(toggleMovieFrames()));
 
  view->setItemChecked(movie_frames_id, par.movie);
 

	
 
  view->setItemChecked(only_boundary_id, FALSE);
 
  menu->insertItem("&View", view);
 

	
 

	
 
  options = new Q3PopupMenu( menu );
 
  dyn_cells_id = options->insertItem("Cell growth", this, SLOT(toggleDynCells()));
 
  options->setItemChecked(dyn_cells_id, true);
 

	
 
  options->insertItem("Edit &parameters", this, SLOT(EditParameters()), Qt::CTRL+Qt::Key_E);
 

	
 
  rotation_mode_id = options->insertItem("Rotate leaf", this, SLOT(EnterRotationMode()), Qt::CTRL + Qt::SHIFT + Qt::Key_R);
 
  options->setItemChecked(rotation_mode_id, false);
 

	
 
  menu->insertItem("&Options",options);
 

	
 
  // Menu of models
 
  modelmenu = new QMenu( menu );
 
  menu->insertItem("&Models", modelmenu);
 

	
 

	
 
  menu->insertSeparator();
 

	
 
  helpmenu = new Q3PopupMenu( menu );
 
  tooltips_id = helpmenu->insertItem("Show Cell&Info", this, SLOT(Refresh()));
 
  helpmenu->setItemChecked(tooltips_id, true);
 
  helpmenu->insertSeparator();
 
  helpmenu->insertItem("&About", this, SLOT(about()) ); //, Key_F1);
 
  helpmenu->insertSeparator();
 
    //helpmenu->insertSeparator();
 
  helpmenu->insertItem("&LICENSE", this, SLOT(gpl()) );
 
  menu->insertItem("&Help",helpmenu);
 
  helpmenu->insertItem("About", this, SLOT(about()) ); //, Key_F1);
 
	
 
	menu->insertItem("&Help",helpmenu);
 
  statusBar();
 
  setCentralWidget(editor);
 
  printer = 0;
 
  init();
 

	
 
  // Start timer which repetitively invokes
 
  // a simulation time step
 
  timer = new QTimer( this );
 
  connect( timer, SIGNAL(timeout()), SLOT(TimeStepWrap()) );
 

	
 
  stopSimulation();
 
  statusBar()->addWidget(new QLabel("Ready."));
 
  setCaption(caption);
 
  gifanim = 0;
 

	
 
  infobar = new InfoBar();
 
  addDockWindow(infobar);
 
}
 

	
 
void Main::RefreshInfoBar(void)
 
{
 
  infobar->SetText(mesh.ModelID());
 
}
 

	
 

	
 
void Main::UserMessage(QString message, int timeout)
 
{
 
  statusBar()->showMessage(message, timeout);
 
}
 

	
 

	
 
void Main::init()
 
{
 
  clear();
 

	
 
  static int r=24;
 
  srand(++r);
 

	
 
  mainCount++;
 
}
 

	
 
Main::~Main()
 
{
 
  delete printer;
 
  if ( !--mainCount ) {
 
  }
 
  //EndGifAnim();
 
}
 

	
 
void Main::newView()
 
{
 
  // Open a new view... have it delete when closed.
 
  Main *m = new Main(canvas, mesh, 0, 0, Qt::WDestructiveClose);
 
  qApp->setMainWidget(m);
 
  m->show();
 
  qApp->setMainWidget(0);
 
}
 

	
 

	
 
void Main::EditParameters()
 
{
 

	
 
  ParameterDialog *pardial = new ParameterDialog(this, "stridediag");
 

	
 
  // Make sure the values in the parameter dialog are updated after a file is read 
 
  // each method changing the parameters (reading XML or PAR files) should
 
  // emit this signal
 
  QObject::connect(   this, SIGNAL( ParsChanged() ), pardial, SLOT( Reset() ) );
 
}
 

	
 
void Main::savePars()
 
{
 

	
 
  stopSimulation();
 

	
 
  Q3FileDialog *fd = new Q3FileDialog( this, "file dialog", TRUE );
 
  fd->setMode( Q3FileDialog::AnyFile );
 
  fd->setFilter( "Parameter files (*.par)");
 

	
 
  QString fileName;
 
  if ( fd->exec() == QDialog::Accepted ) {
 
    fileName = fd->selectedFile();
 
    ofstream parfile((const char *)fileName);
 
    par.Write(parfile);
 
  }
 

	
 
  startSimulation();
 
}
 

	
 
void Main::readPars()
 
{
 

	
 
  stopSimulation();
 

	
 
  Q3FileDialog *fd = new Q3FileDialog( this, "file dialog", TRUE );
 
  fd->setMode( Q3FileDialog::ExistingFile );
 
  fd->setFilter( "Parameter files (*.par)");
 

	
 
  QString fileName;
 
  if ( fd->exec() == QDialog::Accepted ) {
 
    fileName = fd->selectedFile();
 
    par.Read((const char *)fileName);
 
  }
 

	
 
  emit ParsChanged();
 
}
 

	
 

	
 
void Main::saveStateXML()
 
{
 

	
 
  stopSimulation();
 
  Q3FileDialog *fd = new Q3FileDialog( this, "file dialog", TRUE );
 
  fd->setMode( Q3FileDialog::AnyFile );
 
  fd->setFilter( "XML (*.xml)");
 
  QString fileName;
 

	
 
  if ( fd->exec() == QDialog::Accepted ) {
 
    fileName = fd->selectedFile();
 
    if ( QFile::exists( fileName ) &&
 
	 QMessageBox::question(
 
			       this,
 
			       tr("Overwrite File? -- Leaf Growth"),
 
			       tr("A file called %1 already exists."
 
				  "Do you want to overwrite it?")
 
			       .arg( fileName ),
 
			       tr("&Yes"), tr("&No"),
 
			       QString::null, 1, 1 ) ) {
 
      return saveStateXML();
 

	
 
    } else {
 

	
 
      mesh.XMLSave((const char *)fileName, XMLSettingsTree());
 

	
 
    }
 
  }
 
}
 

	
 

	
 

	
 
void Main::snapshot()
 
{
 

	
 

	
 
  stopSimulation();
 
  Q3FileDialog *fd = new Q3FileDialog( this, "Save snapshot", TRUE );
 
  fd->setMode( Q3FileDialog::AnyFile );
 

	
 
  QString fileName;
 

	
 
  if ( fd->exec() == QDialog::Accepted ) {
 
    fileName = fd->selectedFile();
 
    if ( QFile::exists( fileName ) &&
 
	 QMessageBox::question(
 
			       this,
 
			       tr("Overwrite File? -- Leaf Growth"),
 
			       tr("A file called %1 already exists."
 
				  "Do you want to overwrite it?")
 
			       .arg( fileName ),
 
			       tr("&Yes"), tr("&No"),
 
			       QString::null, 1, 1 ) ) {
 
      return snapshot();
 

	
 
    } else {
 

	
 
      // extract extension from filename
 
      QString extension = getExtension(fileName);
 

	
 
      // Save bitmaps at 1024x768
 
      Save((const char *)fileName, extension, 1024, 768);
 
    }
 
  }
 
}
 

	
 

	
 

	
 
void Main::readPrevStateXML()
 
{
 

	
 
  // if we have already read a file, read the next file
 
  if (!currentFile.isEmpty() && working_dir) {
 
    QString next_file;
 

	
 
    QStringList xml_files = working_dir->entryList("*.xml");
 
    QString currentFile_nopath = currentFile.section( '/', -1 );
 
    QString currentFile_path = currentFile.section( '/', 0, -2 );
 

	
 
    QList<QString>::iterator f = xml_files.find( currentFile_nopath );
 

	
 
    if (f == xml_files.end()) {
 
      return;
 
    }
 

	
 
    if (f==xml_files.begin()) {
 
      QMessageBox mb( "Read previous leaf",
 
		      "No more files",
 
		      QMessageBox::Information,
 
		      QMessageBox::Ok | QMessageBox::Default,
 
		      QMessageBox::NoButton,
 
		      QMessageBox::NoButton);
 
      mb.exec();
 
      return;
 
    }
 
    next_file = *(--f);
 
    next_file = currentFile_path+"/"+next_file;
 

	
 
    readStateXML((const char *)next_file);
 

	
 
  }
 
}
 

	
 
int Main::readStateXML(const char *filename, bool geometry, bool pars, bool simtime)
 
{
 

	
 
  try {
 
    xmlNode *settings;
 
    mesh.XMLRead((const char *)filename, &settings, geometry, pars, simtime);
 
#ifdef QDEBUG
 
    qDebug() << "Reading done."<< endl;
 
#endif
 
    XMLReadSettings(settings);
 
    xmlFree(settings);
 
    Cell::SetMagnification(1);
 
    Cell::setOffset(0,0);
 

	
 
    FitLeafToCanvas();
 
    
 
    currentFile =  QString(filename);
 

	
 
    Plot();
 
    QString status_message = QString("Successfully read leaf from file %1. Time is %2 h.").arg(currentFile).arg(mesh.getTimeHours().c_str());
 
    cerr << status_message.toStdString() << endl;
 
    setCaption(caption_with_file.arg(filename));
 
    statusBar()->message(status_message);
 
    emit ParsChanged();
 
#ifdef QDEBUG
 
    qDebug() << "Done. Returning 0." << endl;
 
#endif
 
    return 0;
 
  } catch (const char *error_message) {
 
    QMessageBox mb( "Read leaf from XML file",
 
		    QString(error_message),
 
		    QMessageBox::Critical,
 
		    QMessageBox::Ok | QMessageBox::Default,
 
		    Qt::NoButton,
 
		    Qt::NoButton);
 
    mb.exec();
 
    return 1;
 
  }
 
}
 

	
 

	
 
void Main::readNextStateXML()
 
{
 

	
 
  // if we have already read a file, read the next file
 
  if (!currentFile.isEmpty() && working_dir) {
 
    QString next_file;
 

	
 
    QStringList xml_files = working_dir->entryList("*.xml");
 
    QString currentFile_nopath = currentFile.section( '/', -1 );
 
    QString currentFile_path = currentFile.section( '/', 0, -2 );
 

	
 

	
 
    QList<QString>::iterator f = xml_files.find( currentFile_nopath );
 

	
 
    if (f == xml_files.end()) {
 
      return;
 
    }
 

	
 
    ++f;
 
    if (f==xml_files.end()) {
 
      QMessageBox mb( "Read next leaf",
 
		      "No more files",
 
		      QMessageBox::Information,
 
		      QMessageBox::Ok | QMessageBox::Default,
 
		      QMessageBox::NoButton,
 
		      QMessageBox::NoButton);
 
      mb.exec();
 
      return;
 
    }
 
    next_file = *f;
 
    next_file = currentFile_path+"/"+next_file;
 

	
 
    readStateXML((const char*)next_file);
 
  }
 
}
 

	
 
void Main::readLastStateXML()
 
{
 

	
 
  // if we have already read a file, read the next file
 
  if (!currentFile.isEmpty() && working_dir) {
 
    QString next_file;
 

	
 
    QStringList xml_files = working_dir->entryList("*.xml");
 
    QString currentFile_nopath = currentFile.section( '/', -1 );
 
    QString currentFile_path = currentFile.section( '/', 0, -2 );
 

	
 

	
 
    next_file = xml_files.back();
 

	
 
    next_file = currentFile_path+"/"+next_file;
 

	
 
    readStateXML((const char*)next_file);
 
  }
 
}
 

	
 

	
 
void Main::readFirstStateXML()
 
{
 

	
 
  // if we have already read a file, read the next file
 
  if (!currentFile.isEmpty() && working_dir) {
 
    QString next_file;
 

	
 
    QStringList xml_files = working_dir->entryList("*.xml");
 
    QString currentFile_nopath = currentFile.section( '/', -1 );
 
    QString currentFile_path = currentFile.section( '/', 0, -2 );
 

	
 

	
 
    next_file = xml_files.front();
 

	
 
    next_file = currentFile_path+"/"+next_file;
 

	
 
    readStateXML((const char*)next_file);
 
  }
 
}
 

	
 
void Main::readStateXML()
 
{
 

	
 
  //  extern Mesh mesh;
 

	
 
  stopSimulation();
 
#ifdef QDEBUG
 
  qDebug() << "Trying to open an OptionFileDialog" << endl;
 
#endif
 
  OptionFileDialog *fd = new OptionFileDialog( this, "read dialog", TRUE );
 
  fd->setMode( OptionFileDialog::ExistingFile );
 
  fd->setFilter( "XML files (*.xml)");
 
  if (working_dir) {
 
    fd->setDir(*working_dir);
 
  }
 
  QString fileName;
 
  if ( fd->exec() == QDialog::Accepted ) {
 

	
 
    fileName = fd->selectedFile();
 
    if (working_dir) {
 
      delete working_dir;
 
    }
 
    working_dir = fd->dir();
 

	
 
    if (readStateXML((const char *)fileName,fd->readGeometryP(), fd->readParametersP()) )
 
      return readStateXML(); // user can try again
 
  }
 
}
 

	
 

	
 
void Main::clear()
 
{
 
  editor->clear();
 
}
 

	
 
void Main::about()
 
{
 
  static QMessageBox* about = new QMessageBox
 
    ( "Virtual Leaf V1.0",
 
      "<h3>Virtual Leaf V1.0</h3>"
 
    ( "VirtualLeaf V1.0",
 
      "<h3>VirtualLeaf V1.0</h3>"
 
      "<p>"
 
      "An Open Source framework for cell-based modeling of plant tissue growth and development <br>"
 
      "(c) 2005-2008, Roeland Merks <i>et al.</i><br>"
 
      "    <a href=\"http://www.psb.vib-ugent.be\">VIB Department Plant Systems Biology</a>, "
 
      "Ghent, Belgium <br>"
 
      "(c) 2008-2010, <a href=\"http://www.cwi.nl/~merks\">Roeland Merks <i>et al.</i></a> <br>"
 
      "    <a href=\"http://www.cwi.nl\">Centrum Wiskunde & Informatica</a> and <a href=\"http://www.ncsb.nl\">Netherlands Consortium for Systems Biology</a>, Amsterdam, Netherlands <br>"
 
"<br>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.<br>"
 
"<br>VirtualLeaf 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.<br>"
 
      "<br>If you use this code for your projects, please cite our paper:"
 
"<br>Merks, Guravage, Inze, and Beemster. An Open Source framework for cell-based modeling of plant tissue growth and development. <i>Plant Physiology,</i> submitted.<br> . <br>"
 
      "<br>Please share your model plugins and extensions at <a href=\"http://virtualleaf.googlecode.com\">http://virtualleaf.googlecode.com</a>.", 
 
      QMessageBox::Information, 1, 0, 0, this, 0, FALSE );
 
  about->setButtonText( 1, "Dismiss" );
 
  about->show();
 
}
 

	
 

	
 
void Main::gpl()
 
{
 
  static QMessageBox* gpl = new QMessageBox ( "GPL License", "", 
 
      QMessageBox::Information, 1, 0, 0, this, 0, FALSE );
 

	
 
  QDir docDir(QApplication::applicationDirPath());
 
  docDir.cd("../doc");
 
  QString path = docDir.filePath("gpl3.txt");
 

	
 
  std::ifstream file(path.toStdString().c_str());
 
  std::string str;
 

	
 
  if (file) {
 
    file.seekg(0, std::ios::end);   
 
    str.reserve(file.tellg());
 
    file.seekg(0, std::ios::beg);
 

	
 
    str.assign((std::istreambuf_iterator<char>(file)),
 
	       std::istreambuf_iterator<char>());
 

	
 
    gpl->setDetailedText(QString(str.c_str()));
 
  }
 

	
 
  gpl->setText(QString( "<h3>GNU GENERAL PUBLIC LICENSE</h3>"
 
			"<p>Version 3, 29 June 2007</p>"
 
			"<p>Copyright &copy; 2007 Free Software Foundation, Inc. "
 
			"&lt;<a href=\"http://fsf.org/\">http://fsf.org/</a>&gt;</p><p>"
 
			"Everyone is permitted to copy and distribute verbatim copies "
 
			"of this license document, but changing it is not allowed.</p>"
 
			"<h2>GNU GENERAL PUBLIC LICENSE</h2>"));
 

	
 
  gpl->setButtonText( 1, "Dismiss" );
 
  gpl->show();
 
}
 

	
 
void Main::aboutQt(){
 
  QMessageBox::aboutQt( this, "Virtual Leaf" );
 
}
 

	
 
void Main::toggleShowCellCenters()
 
{
 
  Plot();
 
}
 

	
 
void Main::toggleShowWalls()
 
{
 
  Plot();
 
}
 

	
 
void Main::toggleShowApoplasts()
 
{
 
  Plot();
 
}
 

	
 
void Main::toggleShowNodes()
 
{
 
  Plot();
 
}
 

	
 
void Main::toggleNodeNumbers(void)
 
{
 
  Plot();
 
}
 

	
 
void Main::toggleCellNumbers(void)
 
{
 
  Plot();
 
}
 

	
 
void Main::toggleCellAxes(void)
 
{
 
  Plot();
 
}
 

	
 
void Main::toggleCellStrain(void)
 
{
 
  Plot();
 
}
 

	
 
void Main::toggleShowFluxes(void)
 
{
 
  Plot();
 
}
 

	
 
void Main::toggleShowBorderCells()
 
{
 
  Plot();
 
}
 

	
 
void Main::toggleHideCells(void)
 
{
 
  Plot();
 
  editor->FullRedraw();
 
}
 

	
 
void Main::toggleMovieFrames(){}
 

	
 
void Main::toggleLeafBoundary(){}
 

	
 
void Main::toggleDynCells() {}
 

	
 
void Main::startSimulation(void)
 
{
 
  timer->start( 0 );
 
  statusBar()->message("Simulation started");
 
  running = true;
 
}
 

	
 
void Main::stopSimulation(void)
 
{
 
  timer->stop();
 
  cerr << "Stopping simulation" << endl;
 
  statusBar()->message("Simulation paused");
 
  running = false;
 
}
 

	
 
void Main::togglePaused()
 
{
 
  bool s = run->isItemChecked(paused_id);
 
  if (s) {
 
    cerr << "Calling start simulation" << endl;
 
    startSimulation();
 
  } else {
 
    cerr << "Calling stop simulation" << endl;
 
    stopSimulation();
 
  }
 
}
 

	
 
void Main::setFluxArrowSize(int size)
 
{
 
  flux_arrow_size = size/100.;
 
}
 

	
 

	
 
void Main::enlarge()
 
{
 
  canvas.setSceneRect( QRectF( 0,0, canvas.width()*4./3., canvas.height()*4./3.) );
 
}
 

	
 
void Main::shrink()
 
{
 
  canvas.setSceneRect( QRectF( 0,0, canvas.width()*3/4, canvas.height()*3/4) );
 
}
 

	
 

	
 
void Main::scale(double factor)
 
{
 
  QMatrix m = editor->matrix();
 
  m.scale(factor, factor);
 
  editor->setMatrix( m );
 
}
 

	
 
void Main::zoomIn()
 
{
 
  QMatrix m = editor->matrix();
 
  m.scale( 1.1, 1.1 );
 
  editor->setMatrix( m );
 
}
 

	
 
void Main::zoomOut()
 
{
 
  QMatrix m = editor->matrix();
 
  m.scale( 0.9, 0.9 );
 
  editor->setMatrix( m );
 
}
 

	
 

	
 
void Main::print()
 
{
 
  if ( !printer ) printer = new QPrinter;
 

	
 
  if ( printer->setup(this) ) {
 

	
 
    //    extern Mesh mesh;
 
    Vector bbll,bbur;
 
    mesh.BoundingBox(bbll,bbur);
 

	
 
#ifdef QDEBUG
 
    qDebug() << "bbll = " << bbll << endl;
 
    qDebug() << "bbur = " << bbur << endl;
 
#endif
 
    double cw = (bbur.x - bbll.x);
 
    double ch = (bbur.y - bbll.y);
 
    QPainter pp(printer);
 
    QRect vp=pp.viewport();
 
#ifdef QDEBUG
 
    qDebug() << "Paper width = " << vp.width() << " x " << vp.height() << endl;
 
#endif
 

	
 
    // Note that Cell is also translated...
 
    pp.translate(-bbur.x,-bbur.y);
 
    if (cw>ch) {
 
      pp.scale(vp.width()/(2*cw*Cell::Magnification()), vp.width()/(2*cw*Cell::Magnification()));
 
    } else {
 
      pp.scale(vp.height()/(2*ch*Cell::Magnification()), vp.height()/(2*ch*Cell::Magnification()));
 
    }
 
    canvas.render(&pp, QRectF(), QRectF(0.,0.,canvas.width(),canvas.height()));
 
  }
 
}
 

	
 

	
 
void Main::TimeStepWrap(void)
 
{
 
  static int t=0;
 
  TimeStep();
 
  t++;
 
  // check number of timesteps
 
  if (t==par.nit) {
 
    emit SimulationDone();
 
  }
 
}
 

	
 

	
 
void Main::RestartSim(void)
 
{
 

	
 
  stopSimulation();
 
  if ( QMessageBox::question(
 
			     this,
 
			     tr("Restart simulation?"),
 
			     tr("Restart simulation.\n"
 
				"Are you sure?"),
 
			     QMessageBox::Yes | QMessageBox::No, QMessageBox::NoButton ) == QMessageBox::Yes ) {
 

	
 
    cerr << "Restarting simulation" << endl;
 
    //    extern Mesh mesh;
 
    mesh.Clear();
 
    Init();
 
    Plot();
 
    editor->FullRedraw();
 
  } 
 
  //startSimulation();
 
}
 

	
 

	
 
void Main::FitCanvasToWindow(void)
 
{
 

	
 
  double scale_factor_x = (double)editor->width()/(double)canvas.width();
 
  double scale_factor_y = (double)editor->height()/(double)canvas.height();
 
  double scale_factor = scale_factor_x > scale_factor_y ? scale_factor_x : scale_factor_y;
 
  QMatrix m = editor->matrix();
 

	
 
#ifdef QDEBUG  
 
  qDebug() << "editor->width() = " << editor->width() << endl;
 
  qDebug() << "editor->height() = " << editor->height() << endl;
 

	
 
  qDebug() << "scale_factor = " << scale_factor << endl;
 
  qDebug() << "scale_factor_x = " << scale_factor_x << endl;
 
  qDebug() << "scale_factor_y = " << scale_factor_y << endl;
 
#endif
 
  m.scale( scale_factor, scale_factor );
 
  editor->setMatrix( m );
 
  editor->show();
 
}
 

	
 
void Main::PauseIfRunning(void)
 
{
 
  if (running) {
 
    timer->stop();
 
  }
 
}
 

	
 
void Main::ContIfRunning(void)
 
{
 
  if (running) {
 
    timer->start( 0 );
 
  }
 
}
 

	
 
void Main::FitLeafToCanvas(void) 
 
{
 

	
 
  Vector ll,ur;
 
  mesh.BoundingBox(ll, ur);
 

	
 
  ll*=Cell::Magnification(); ur*=Cell::Magnification();
 

	
 
  // give the leaf some space
 
  Vector border = ((ur-ll)/5.);
 

	
 
  QRectF bb( ll.x - border.x, ll.y - border.y, ur.x-ll.x + 2*border.x, ur.y-ll.y + 2*border.y );
 

	
 

	
 
  // cerr << ur << ", " << ll << endl;
 
  // editor->fitInView(bb, Qt::KeepAspectRatio);
 
  editor->ensureVisible(bb);
 
  //editor->setTransform(viewport);
 
}
 

	
 
void Main::CleanMesh(void) 
 
{
 
  vector<double> clean_chem(Cell::NChem());
 
  vector<double> clean_transporters(Cell::NChem());
 

	
 
  for (int i=0;i<Cell::NChem();i++) {
 
    clean_chem[i]=par.initval[i];
 
    clean_transporters[i]=0.;		
 
  }
 

	
 
  mesh.CleanChemicals(clean_chem);
 
  mesh.CleanTransporters(clean_transporters);
 

	
 
  mesh.setTime(0);
 
  Plot();
 

	
 
  editor->FullRedraw();
 
}
 

	
 
void Main::CleanMeshChemicals(void) 
 
{
 

	
 
  vector<double> clean_chem(Cell::NChem());
 

	
 
  for (int i=0;i<Cell::NChem();i++) {
 
    clean_chem[i]=par.initval[i];
 
  }
 

	
 
  mesh.CleanChemicals(clean_chem);
 
  mesh.setTime(0);
 
  Plot();
 

	
 
  editor->FullRedraw();
 
}
 

	
 
void Main::CleanMeshTransporters(void) 
 
{
 
  vector<double> clean_transporters(Cell::NChem());
 
  for (int i=0;i<Cell::NChem();i++) {
 
    clean_transporters[i]=0.;
 
  }
 

	
 
  mesh.CleanTransporters(clean_transporters);
 

	
 
  mesh.setTime(0);
 
  Plot();
 

	
 
  editor->FullRedraw();
 
}
 

	
 
void Main::RandomizeMesh(void) 
 
{
 

	
 
  vector<double> max_chem(Cell::NChem());
 
  vector<double> max_transporters(Cell::NChem());
 

	
 
  for (int i=0;i<Cell::NChem();i++) {
 
    max_transporters[i]=0.;
 
    max_chem[i]=par.initval[i];
 
  }
 

	
 
  // Amount of PIN1 at walls
 
  max_transporters[1] = 0.01;
 

	
 
  mesh.RandomizeChemicals(max_chem, max_transporters);
 

	
 
  Plot();
 
}
 

	
 
void Main::XMLReadSettings(xmlNode *settings) 
 
{
 

	
 
  MainBase::XMLReadSettings(settings);
 
  
 
  view->setItemChecked(com_id, showcentersp);
 
  view->setItemChecked(mesh_id, showmeshp);
 
  view->setItemChecked(border_id, showbordercellp);
 
  view->setItemChecked(node_number_id, shownodenumbersp);
 
  view->setItemChecked(cell_number_id, showcellnumbersp);
 
  view->setItemChecked(cell_axes_id, showcellsaxesp);
 
  view->setItemChecked(cell_strain_id, showcellstrainp);
 
  view->setItemChecked(movie_frames_id, movieframesp);
 
  view->setItemChecked(only_boundary_id, showboundaryonlyp);
 
  view->setItemChecked(fluxes_id, showfluxesp);
 
  view->setItemChecked(hide_cells_id, hidecellsp);
 
  options->setItemChecked(dyn_cells_id, dynamicscellsp);
 
  view->setItemChecked( cell_walls_id, showwallsp);
 
  view->setItemChecked( apoplasts_id, showapoplastsp);
 
 // view->setItemChecked( apoplasts_id, showapoplastsp);
 
  
 
  editor->setTransform(viewport);
 
}
 

	
 
xmlNode *Main::XMLSettingsTree(void) 
 
{
 

	
 
  showcentersp = view->isItemChecked(com_id);
 
  showmeshp = view->isItemChecked(mesh_id);
 
  showbordercellp =  view->isItemChecked(border_id);
 
  shownodenumbersp =  view->isItemChecked(node_number_id);
 
  showcellnumbersp =  view->isItemChecked(cell_number_id);
 
  showcellsaxesp = view->isItemChecked( cell_axes_id );
 
  showcellstrainp = view->isItemChecked( cell_strain_id );
 
  movieframesp = view->isItemChecked(movie_frames_id);;
 
  showboundaryonlyp =  view->isItemChecked(only_boundary_id);
 
  showfluxesp = view->isItemChecked(fluxes_id);
 
  dynamicscellsp = options->isItemChecked(dyn_cells_id);
 
  showwallsp = view->isItemChecked( cell_walls_id);
 
  showapoplastsp = view->isItemChecked( apoplasts_id);
 
  //showapoplastsp = view->isItemChecked( apoplasts_id);
 
  hidecellsp = view->isItemChecked( hide_cells_id);
 

	
 
  xmlNode *settings = MainBase::XMLSettingsTree();
 
  QTransform viewport(editor->transform());
 
  xmlAddChild(settings, XMLViewportTree(viewport));
 
  return settings;
 
}
 

	
 
/* finis */
src/canvas.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  This file is part of the Virtual Leaf.
 
 *
 
 *  The Virtual Leaf is free software: you can redistribute it and/or modify
 
 *  VirtualLeaf 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,
 
 *  VirtualLeaf 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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#ifndef _CANVAS_H_
 
#define _CANVAS_H_
 

	
 
#include <q3popupmenu.h>
 
#include <q3mainwindow.h>
 
#include <q3intdict.h>
 
#include <QGraphicsScene>
 
#include <QGraphicsView>
 
#include <QList>
 

	
 
#include <string>
 
#include <sstream>
 

	
 
//Added by qt3to4:
 
#include <QMouseEvent>
 
#include <vector>
 
#include "simitembase.h"
 
#include "mainbase.h"
 
#include "cellitem.h"
 
#include "infobar.h"
 

	
 
#include "nodeitem.h"
 
#include "cell.h"
 

	
 
#ifdef HAVE_QWT
 
#include "data_plot.h"
 
#endif
 

	
 
#include <libxml/xpath.h>
 
#include <libxml/xmlreader.h>
 

	
 
#if defined(Q_OS_MAC)
 
#define PREFIX "cmd"
 
#else
 
#define PREFIX "crtl"
 
#endif
 

	
 

	
 
class QFile;
 
class QDir;
 
class ModelCatalogue;
 
class InfoBar;
 

	
 
class FigureEditor : public QGraphicsView {
 
  Q_OBJECT
 

	
 
    friend class Main;
 
 public:
 
  FigureEditor(QGraphicsScene&, Mesh&, QWidget* parent=0, const char* name=0, Qt::WFlags f=0);
 
  void clear();
 
  void Save(const char *fname, const char *format, int sizex=640, int sizey=480);
 
  void FullRedraw(void);
 

	
 
 protected:
 
  void mousePressEvent(QMouseEvent*);
 
  void mouseMoveEvent(QMouseEvent*);
 
  void mouseReleaseEvent(QMouseEvent*);
 
  void wheelEvent(QWheelEvent *event);
 
  void scaleView(qreal scaleFactor);
 

	
 
  vector <CellItem *> getIntersectedCells(void);
 
  void insertNode(QPointF p);
 
  NodeItem *selectedNodeItem(QList<QGraphicsItem *> l) const;  
 

	
 
 signals:
 
  void status(const QString&);
 
  void MousePressed(void);
 
  void MouseReleased(void);
 
 protected:
 
  Mesh &mesh;
 

	
 
 private:
 
  //NodeItem* moving;
 
  SimItemBase *moving;
 
  QPointF moving_start;
 

	
 
  QGraphicsLineItem *intersection_line;
 
  bool rotation_mode;
 
  bool insert_mode;
 
  double rot_angle;
 
};
 

	
 
class Main : public Q3MainWindow, public MainBase {
 
  Q_OBJECT
 
    friend class ModelCatalogue; // needs to populate menu item models
 
 public:
 
  Main(QGraphicsScene&, Mesh&, QWidget* parent=0, const char* name=0, Qt::WFlags f=0);
 
  ~Main();
 
  virtual bool ShowCentersP(void) {return view->isItemChecked(com_id);}
 
  virtual bool ShowMeshP(void) {return view->isItemChecked(mesh_id);}
 
  virtual bool ShowBorderCellsP(void) {return view->isItemChecked(border_id);}
 
  virtual bool PausedP(void) {return run->isItemChecked(paused_id);}
 
  virtual bool ShowNodeNumbersP(void) {return view->isItemChecked(node_number_id);}
 
  virtual bool ShowCellNumbersP(void) {return view->isItemChecked(cell_number_id);}
 
  virtual bool ShowCellAxesP(void) {return view->isItemChecked(cell_axes_id);}
 
  virtual bool ShowCellStrainP(void) {return view->isItemChecked(cell_strain_id);}
 
  virtual bool MovieFramesP(void) {return view->isItemChecked(movie_frames_id);}
 
  virtual bool ShowBoundaryOnlyP(void) {return view->isItemChecked(only_boundary_id);}
 
  virtual bool ShowWallsP(void) {return view->isItemChecked(cell_walls_id);}
 
  virtual bool ShowApoplastsP(void) { return view->isItemChecked(apoplasts_id);}
 
 // virtual bool ShowApoplastsP(void) { return view->isItemChecked(apoplasts_id);}
 
  virtual bool ShowFluxesP(void) { return view->isItemChecked(fluxes_id); }
 
  virtual bool DynamicCellsP(void) { return options->isItemChecked(dyn_cells_id); }
 
  virtual bool RotationModeP(void) { return options->isItemChecked(rotation_mode_id); }
 
  virtual bool InsertModeP(void) { return options->isItemChecked(insert_mode_id); }
 
  virtual bool ShowToolTipsP(void) { return helpmenu->isItemChecked(tooltips_id); }
 
  virtual bool HideCellsP(void) { return view->isItemChecked(hide_cells_id); }
 
  void scale(double factor); 
 
  virtual double getFluxArrowsize(void)
 
  {
 
    return flux_arrow_size;
 
  }
 

	
 
  void FitCanvasToWindow();
 
  void FitLeafToCanvas(void);
 

	
 

	
 
  public slots:
 

	
 
  void about();
 
  void gpl();
 
  void TimeStepWrap();
 
  void togglePaused();
 
  void setFluxArrowSize(int size);
 
  void RestartSim(void);
 
  void toggleShowCellCenters(void);
 
  void toggleShowNodes(void);
 
  void toggleShowBorderCells(void);
 
  void toggleShowFluxes(void);
 
  void toggleNodeNumbers(void);
 
  void toggleCellNumbers(void);
 
  void toggleCellAxes(void);
 
  void toggleCellStrain(void);
 
  void toggleShowWalls(void);
 
  void toggleShowApoplasts(void);
 
  void toggleDynCells(void);
 
  void toggleMovieFrames(void);
 
  void toggleLeafBoundary(void);
 
  void toggleHideCells(void);
 
  void print();
 
  void startSimulation(void);
 
  void stopSimulation(void);
 
  void RefreshInfoBar(void);
 

	
 
  void EnterRotationMode(void)
 
  {
 

	
 
    UserMessage("Rotation mode. Click mouse to exit.");
 
    if (editor) {
 
      editor->rot_angle = 0. ; 
 

	
 
      // Exit rotation mode if mouse is clicked
 
      connect(editor, SIGNAL(MousePressed()), this, SLOT(ExitRotationMode()));
 
      
 
      editor->setMouseTracking(true);
 

	
 
    }
 

	
 
  }
 
  void ExitRotationMode(void)
 
  { 
 
    UserMessage("Exited rotation mode.",2000);
 

	
 
    options->setItemChecked(rotation_mode_id, false); 
 
    if (editor)
 
      disconnect(editor, SIGNAL(MousePressed()), this, SLOT(ExitRotationMode()));
 
    editor->setMouseTracking(false);
 
 
 
  }
 

	
 
  virtual void UserMessage(QString message, int timeout=0);
 
  void Refresh(void) { Plot(); }
 
  void PauseIfRunning(void);
 
  void ContIfRunning(void);
 
  virtual void XMLReadSettings(xmlNode *settings);
 

	
 
  private slots:
 
  void aboutQt();
 
  void newView();
 
  void EditParameters();
 
  void readStateXML();
 
  int readStateXML(const char *filename, bool geometry = true, bool pars=true, bool simtime = true);
 
  void readNextStateXML();
 
  void readPrevStateXML();
 
  void readFirstStateXML();
 
  void readLastStateXML();
 
  void saveStateXML();
 
  void snapshot();
 
  void savePars();
 
  void readPars();
 
  void clear();
 
  void init();
 
  virtual void CutSAM() { MainBase::CutSAM(); Refresh();}
 

	
 
  void enlarge();
 
  void shrink();
 
  void zoomIn();
 
  void zoomOut();
 

	
 
  void CleanMesh();
 
  void CleanMeshChemicals(void);
 
  void CleanMeshTransporters(void);
 

	
 
  void RandomizeMesh();
 

	
 
 signals:
 
  void SimulationDone(void);
 
  void ParsChanged(void);
 

	
 
 protected:
 
  Mesh &mesh;
 

	
 
 private:
 
  NodeSet *node_set;
 
  FigureEditor *editor;
 
  Q3PopupMenu* options;
 
  Q3PopupMenu *view;
 
  Q3PopupMenu *run;
 
  QMenu *modelmenu;
 
  Q3PopupMenu *helpmenu;
 

	
 
  QPrinter* printer;
 
  const QDir *working_dir;
 
  QString currentFile;
 
  //  toggle item states 
 
  int dbf_id; // options->Double Buffer
 
  int com_id; // view->Show centers
 
  int mesh_id; // view->Show mesh
 
  int node_number_id; // view->Show Node numbers
 
  int cell_number_id; // view->Show Cell numbers
 
  int border_id; // view->Show border cells
 
  int paused_id; // run->Simulation paused
 
  int cell_axes_id; // view->Show cell axes
 
  int cell_strain_id; // view->Show cell strain
 
  int only_boundary_id; // view ->Show only leaf boundary
 
  int cell_walls_id; // view -> Show transporters
 
  int apoplasts_id; // view -> Show apoplasts
 
  //int apoplasts_id; // view -> Show apoplasts
 
  int tooltips_id; // help -> Show Cell Info
 
  int hide_cells_id; // view->Hide Cells
 
  double flux_arrow_size;
 
  int movie_frames_id;
 
  int fluxes_id;
 
  int dyn_cells_id;
 
  int rotation_mode_id;
 
  int insert_mode_id;
 
  QTimer *timer;
 
  QFile *gifanim;
 
  bool running;
 
  virtual xmlNode *XMLSettingsTree(void);
 
  static const QString caption;
 
  static const QString caption_with_file;
 
  InfoBar *infobar;
 
};
 

	
 
#endif
 

	
 
/* finis*/
src/cell.cpp
Show inline comments
 
/*
 
 *
 
 *  This file is part of the Virtual Leaf.
 
 *
 
 *  The Virtual Leaf is free software: you can redistribute it and/or modify
 
 *  VirtualLeaf 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,
 
 *  VirtualLeaf 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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include <QDebug>
 

	
 
#include <string>
 
#include "cell.h"
 
#include "node.h"
 
#include "mesh.h"
 
#include "tiny.h"
 
#include "nodeset.h"
 
#include "cellitem.h"
 
#include "nodeitem.h"
 
#include "qcanvasarrow.h"
 
#include "parameter.h"
 

	
 

	
 
static const std::string _module_id("$Id$");
 

	
 
extern Parameter par;
 

	
 
double Cell::factor=1.;
 
double Cell::offset[3]={0,0,0};
 

	
 
Cell::Cell(void) : CellBase()
 
{
 
  m=0;
 
}
 

	
 
Cell::Cell(double x, double y, double z) : CellBase(x,y,z)
 
{
 
  m=0;
 
}
 

	
 
Cell::Cell(const Cell &src) :  CellBase(src)
 
{
 
  m=src.m;
 
}
 

	
 
bool Cell::Cmp(Cell *c) const { return this->Index() < c->Index(); }
 
bool Cell::Eq(Cell *c) const { return this->Index() == c->Index(); }
 

	
 
Cell Cell::operator=(const Cell &src) 
 
{
 
  CellBase::operator=(src);
 
  m=src.m;
 
  return *this;
 
}
 
//Cell(void) : CellBase() {}
 

	
 
void Cell::DivideOverAxis(Vector axis) 
 
{
 
  // Build a wall
 
  // ->  find the position of the wall
 

	
 
  // better look for intersection with a simple line intersection algorithm as below?
 
  // this leads to some exceptions: e.g. dividing a horizontal rectangle.
 
  // leaving it like this for the time being
 

	
 
  if (dead) return;
 

	
 
  Vector centroid=Centroid();
 
  double prev_cross_z=(axis * (centroid - *(nodes.back()) ) ).z ;
 

	
 
  ItList new_node_locations;
 

	
 
  for (list<Node *>::iterator i=nodes.begin(); i!=nodes.end(); i++) {
 

	
 
    // cross product to detect position of division
 
    Vector cross = axis * (centroid - *(*i));
 

	
 
    if (cross.z * prev_cross_z < 0 ) {
 

	
 
      new_node_locations.push_back(i);
 

	
 
    }		
 
    prev_cross_z=cross.z;
 
  }
 

	
 
  DivideWalls(new_node_locations, centroid, centroid+axis);
 
}
 

	
 
double Cell::MeanArea(void)
 
{
 
  return m->MeanArea();
 
}
 

	
 

	
 
void Cell::Apoptose(void)
 
{
 
  // First kill walls
 
#ifdef QDEBUG
 
  qDebug() << "This is cell " << Index() << endl;
 
  qDebug() << "Number of walls: " << walls.size() << endl;
 
#endif
 
  for (list<Wall *>::iterator w=walls.begin(); w!=walls.end(); w++) {
 
#ifdef QDEBUG
 
    qDebug() << "Before apoptosis, wall " << (*w)->Index() << " says: c1 = "
 
	     << (*w)->c1->Index() << ", c2 = " << (*w)->c2->Index() << endl;
 
#endif
 
  }
 
  for (list<Wall *>::iterator w=walls.begin(); w!=walls.end(); w++) {
 

	
 
    bool illegal_flag = false;
 
    if ((*w)->c1 == (*w)->c2 ) 
 
      illegal_flag=true;
 
    if ((*w)->c1 == this) {
 

	
 
      // invert wall?
 
      (*w)->c1 = (*w)->c2;      
 
      (*w)->c2 = m->boundary_polygon;
 

	
 
      Node *n1 = (*w)->n1;
 
      (*w)->n1 = (*w)->n2;
 
      (*w)->n2 = n1;
 

	
 
    } else {
 
      (*w)->c2 = m->boundary_polygon;
 
    }
 

	
 
#ifdef QDEBUG
 
    if (illegal_flag && (*w)->c1==(*w)->c2) {
 
      qDebug() << "I created an illegal wall." << endl;
 
    }
 
#endif
 

	
 
    if ( ((*w)->N1()->DeadP() || (*w)->N2()->DeadP()) ||
 
	 ((*w)->C1() == (*w)->C2() ) ){
 
      // kill wall
 
#ifdef QDEBUG
 
      qDebug() << "Killing wall." << endl;
 
#endif
 
      (*w)->Kill();
 

	
 
#ifdef QDEBUG
 
      if ((*w)) {
 
	qDebug() << "Wall " << (*w)->Index() << " says: c1 = " 
 
		 << (*w)->c1->Index() << ", c2 = " << (*w)->c2->Index() << endl;
 
      }
 
#endif
 
      (*w)=0;
 
    } else {
 
#ifdef QDEBUG
 
      qDebug() << "Not killing wall." << endl;
 
      qDebug() << "Wall " << (*w)->Index() << " says: c1 = " 
 
	       << (*w)->c1->Index() << ", c2 = " << (*w)->c2->Index() << endl;
 
#endif
 
    }
 
  }
 
  walls.remove(0);
 

	
 
  // Unregister me from my nodes, and delete the node if it no longer belongs to any cells
 
  list<Node *> superfluous_nodes;
 
  for (list<Node *>::iterator n=nodes.begin(); n!=nodes.end(); n++) {
 

	
 
    Node &no(*(*n));
 
    // locate myself in the node's owner list
 
    list<Neighbor>::iterator cellpos;
 
    bool cell_found=false;
 
    for (list<Neighbor>::iterator nb=no.owners.begin(); nb!=no.owners.end(); nb++) {
 
      if (nb->cell == this) {
 
	cellpos = nb;
 
	cell_found = true;
 
	break;
 
      }
 
    }
 

	
 
    if (!cell_found) {
 
      // I think this cannot happen; but if I am wrong, unpredictable things would happen. So throw an exception.
 
      throw ("Cell not found in CellBase::Apoptose()\n\rPlease correct the code to handle this situation.");
 
    }
 

	
 
    Neighbor tmp = *cellpos;
 
    no.owners.erase(cellpos);
 

	
 
    // if node has no owners left, or only has a connection to special cell -1 (outside world), mark it as dead.
 

	
 
    if (no.owners.size()==0 || (no.owners.size()==1 && no.owners.front().cell->BoundaryPolP()) ) {
 
      no.MarkDead();
 
    } else {
 
      // register node with outside world
 
      if (find_if( no.owners.begin(), no.owners.end(), 
 
		   bind2nd ( mem_fun_ref(&Neighbor::CellEquals), m->boundary_polygon->Index() ) ) == no.owners.end() ) {
 

	
 
	tmp.cell = m->boundary_polygon;
 
	no.owners.push_back(tmp);
 
      }
 
    }
 
  }
 

	
 
  // mark cell as dead
 
  MarkDead();
 
}
 

	
 
void Cell::ConstructConnections(void)
 
{
 
  // Tie up the nodes of this cell, assuming they are correctly ordered
 

	
 
  //cerr << "Constructing connections of cell " << index << endl;
 

	
 
  for (list<Node *>::iterator i=nodes.begin(); i!=nodes.end(); i++) {
 

	
 
    //cerr << "Connecting node " << *i << endl;
 
    //cerr << "Node " << *i << endl << " = " << *(*i) << endl;
 
    // 1. Tidy up existing connections (which are part of this cell)
 
    if ((*i)->owners.size()>0) {
 
      list<Neighbor>::iterator neighb_with_this_cell=
 
	// remove myself from the neighbor list of the node
 
	find_if((*i)->owners.begin(),
 
		(*i)->owners.end(),
 
		bind2nd(mem_fun_ref( &Neighbor::CellEquals ),this->Index() )  );
 
      if (neighb_with_this_cell!=(*i)->owners.end()) 
 
	(*i)->owners.erase(neighb_with_this_cell);
 
    }
 

	
 
    Node *previous;
 
    if (i!=nodes.begin()) {
 
      list<Node *>::iterator previous_iterator=i;
 
      previous_iterator--;
 
      previous=*previous_iterator;
 
    } else {
 
      previous=nodes.back();
 
    }
 

	
 
    Node *next;
 
    list<Node *>::iterator next_iterator=i;
 
    next_iterator++;
 
    if (next_iterator==nodes.end()) {
 
      next=nodes.front();
 
    } else {
 
      next=*next_iterator;
 
    }
 
    (*i)->owners.push_back( Neighbor( this, previous, next ) );
 
  }
 
}
 

	
 
bool Cell::DivideOverGivenLine(const Vector v1, const Vector v2, bool fix_cellwall, NodeSet *node_set )
 
{
 
  if (dead) return false;
 

	
 
  // check each edge for intersection with the line
 
  ItList new_node_locations;
 

	
 
#ifdef QDEBUG
 
  qDebug() << "Cell " << Index() << " is doing DivideOverGivenLine" << endl;
 
#endif
 
  for (list<Node *>::iterator i=nodes.begin(); i!=nodes.end(); i++) {
 

	
 
    Vector v3 = *(*i);
 
    list<Node *>::iterator nb=i;
 
    nb++;
 
    if (nb == nodes.end()) {
 
      nb = nodes.begin();
 
    }
 
    Vector v4 = *(*nb);
 

	
 
    double denominator = 
 
      (v4.y - v3.y)*(v2.x - v1.x) - (v4.x - v3.x)*(v2.y - v1.y);
 

	
 
    double ua = 
 
      ((v4.x - v3.x)*(v1.y - v3.y) - (v4.y - v3.y)*(v1.x -v3.x))/denominator;
 
    double ub = 
 
      ((v2.x - v1.x)*(v1.y-v3.y) - (v2.y- v1.y)*(v1.x - v3.x))/denominator;
 

	
 

	
 
    //cerr << "Edge " << *i << " to " << *nb << ": ua = " << ua << ", ub = " << ub << ":  ";
 
    // this construction with "TINY" should simulate open/closed interval <0,1]
 
    if ( ( TINY < ua && ua < 1.+TINY ) && ( TINY < ub && ub < 1.+TINY ) ) {
 
      // yes, intersection detected. Push the location to the list of iterators
 
      new_node_locations.push_back(nb);
 

	
 
    } 
 
  }
 

	
 
#ifdef QDEBUG
 
  if (new_node_locations.size()<2) { 
 
    qDebug() << "Line does not intersect with two edges of Cell " << Index() << endl;
 
    qDebug() << "new_node_locations.size() = " << new_node_locations.size() << endl;
 
    return false;
 
  }
 

	
 
  ItList::iterator i = new_node_locations.begin();
 
  list< Node *>::iterator j;
 
  qDebug() << "-------------------------------" << endl;
 
  qDebug() << "Location of new nodes: " << (**i)->Index() << " and ";
 

	
 
  ++i;
 
  j = *i; 
 
  if (j==nodes.begin()) j=nodes.end(); j--;
 

	
 
  qDebug() << (*j)->Index() << endl;
 
  qDebug() << "-------------------------------" << endl;
 

	
 
  if ( **new_node_locations.begin() == *j ) {
 
    qDebug() << "Rejecting proposed division (cutting off zero area)." << endl;
 
    return false;
 
  }
 
#endif
 

	
 
  DivideWalls(new_node_locations, v1, v2, fix_cellwall, node_set);
 

	
 
  return true;
 
}
 

	
 
// Core division procedure
 
void Cell::DivideWalls(ItList new_node_locations, const Vector from, const Vector to, bool fix_cellwall, NodeSet *node_set)
 
{
 

	
 
  if (dead) return;
 

	
 
  bool boundary_touched_flag=false;
 

	
 
  // Step 0: keep some data about the parent before dividing
 

	
 
  ParentInfo parent_info;
 
  parent_info.polarization = ReduceCellAndWalls<Vector>( PINdir );
 
  parent_info.polarization.Normalise();
 
  parent_info.PINmembrane = SumTransporters(1);
 
  parent_info.PINendosome = Chemical(1);
 

	
 
  //cerr << "Parent polarization before division: " << parent_info.polarization << endl;
 

	
 
  // Step 1: create a daughter cell
 
  Cell *daughter=m->AddCell(new Cell());
 

	
 
  // Step 2: Copy the basics of parent cell to daughter
 
  for (int i=0;i<NChem();i++) {
 
    daughter->chem[i]=chem[i];
 
  }
 

	
 
  daughter->cell_type = cell_type;
 

	
 
  for (int i=0;i<NChem();i++) {
 
    daughter->new_chem[i]=new_chem[i];
 
  }
 

	
 
  daughter->boundary=boundary;
 
  daughter->m=m;
 

	
 
  daughter->target_area=target_area/2.;
 

	
 
  target_area/=2;
 
  daughter->cellvec=cellvec;
 

	
 
  // Division currently only works for convex cells: i.e. if the division line
 
  // intersects the cells at two points only.
 
  if (new_node_locations.size()!=2) {
 

	
 
    // Note: if you would add the possibility of dividing non-convex
 
    // cells, remember to update the code below. There are some
 
    // fixed-size arrays over there!
 

	
 
    cerr << "Warning in Cell::Division: division of non-convex cells not fully implemented" << endl;
 

	
 
    // Reject the daughter cell and decrement the amount of cells
 
    // again. We can do this here because it is the last cell added.
 
    // Never, ever try to fully erase a cell elsewhere, because we
 
    // make heavy use of cell indices in this project; if you erase a
 
    // Cell somewhere in the middle of Mesh::Cells the indices will
 
    // get totally messed up...! (e.g. the indices used in Nodes::cells)
 

	
 
#ifdef QDEBUG
 
    qDebug() << "new_node_locations.size() = " << new_node_locations.size() <<endl;
 
    qDebug() << "daughter->index = " << daughter->index << endl;
 
    qDebug() << "cells.size() = " << m->cells.size() << endl;
 
#endif
 

	
 
    m->cells.pop_back();
 
    Cell::NCells()--;
 
    m->shuffled_cells.pop_back();
 
    return;
 
  }
 

	
 
  // We can be sure we only need two positions here because divisions
 
  // of non-convex cells are rejected above.
 
  Vector new_node[2];
 
  Node *new_node_ind[2];
 

	
 
  int new_node_flag[2];
 
  Edge div_edges[2];
 

	
 
  int nnc=0;
 

	
 
  Wall *div_wall[4];
 
  double orig_length[2];
 
  for (int i=0;i<4;i++) { div_wall[i]=0; orig_length[i/2] = 0.; }
 

	
 
  // construct new Nodes at the intersection points
 
  // unless they coincide with existing points
 
  for ( ItList::const_iterator i=new_node_locations.begin(); i!=new_node_locations.end(); i++) {
 

	
 
    // intersection between division axis
 
    // and line from this node to its predecessor
 

	
 
    // method used: http://astronomy.swin.edu.au/~pbourke/geometry/lineline2d/
 
    Vector v1 = from;
 
    Vector v2 = to;
 
    Vector v3 = *(**i);
 

	
 
    // get previous node
 
    list<Node *>::iterator nb=*i;
 
    if (nb == nodes.begin()) {
 
      nb = nodes.end();
 
    } 
 
    nb--;
 
    Vector v4=*( *nb ); 
 

	
 
    double denominator = 
 
      (v4.y - v3.y)*(v2.x - v1.x) - (v4.x - v3.x)*(v2.y - v1.y);
 

	
 
    double ua = 
 
      ((v4.x - v3.x)*(v1.y - v3.y) - (v4.y - v3.y)*(v1.x -v3.x))/denominator;
 

	
 
    double intersec_x = v1.x + ua*(v2.x-v1.x);
 
    double intersec_y = v1.y + ua*(v2.y-v1.y);
 

	
 
    // construct a new node at intersec
 
    // we construct a vector temporarily,
 
    // until we are sure we are going to keep the node...
 
    // Node count is damaged if we construct superfluous nodes
 
    Vector *n=new Vector(intersec_x,intersec_y,0);
 

	
 
    div_edges[nnc].first=*nb;
 
    div_edges[nnc].second=**i;
 

	
 
    // Insert this new Node if it is far enough (5% of element length)
 
    // from one of the two existing nodes, else use existing node
 
    //
 
    // old, fixed value was: par.collapse_node_threshold = 0.05
 
    double collapse_node_threshold = 0.05;
 
#ifdef FLEMING
 
    collapse_node_threshold = par.collapse_node_threshold;
 
#endif
 

	
 
    double elem_length = ( (*(**i)) - (*(*nb)) ).Norm();
 
    if ( ( *(**i) - *n ).Norm() < collapse_node_threshold  * elem_length ) {
 
      new_node_flag[nnc]=1;
 
      new_node[nnc] = *(**i);
 
      new_node_ind[nnc] = **i;
 
      //cerr << **i << endl ;
 
    } else 
 
      if ( (*(*nb) - *n).Norm() < collapse_node_threshold * elem_length ) {
 
	new_node_flag[nnc]=2;
 
	new_node[nnc] = *(*nb);
 
	new_node_ind[nnc] = *nb;
 
      } else {
 
	new_node_flag[nnc]=0;
 
	new_node[nnc] = *n;
 
      }
 

	
 
    nnc++;
 
    delete n;
 
  }
 

	
 

	
 
  for (int i=0;i<2;i++) {
 

	
 
    Cell *neighbor_cell=0; // we need this to split up the "Wall" objects.
 

	
 
    // for both divided edges: 
 
    //      insert its new node into all cells that own the divided edge
 
    // but only if it really is a new node:
 
    if (new_node_flag[i]!=0) {
 
      if (fix_cellwall) {
 
	(new_node_ind[i])->fixed = true;
 

	
 
	// all this we'll do later for the node set :-)
 
	/* (new_node_ind[i])->boundary = true;
 
	   (new_node_ind[i])->sam = true;
 
	   boundary = SAM;
 
	   daughter->boundary = SAM;
 
	   boundary_touched_flag = true;
 
	*/ 
 
      }
 

	
 
    } else {
 

	
 
      // (Construct a list of all owners:)
 
      // really construct the new node (if this is a new node)
 
      new_node_ind[i] = 
 
	m->AddNode(new Node (new_node[i]) );
 

	
 

	
 

	
 
      // if a new node is inserted into a fixed edge (i.e. in the petiole)
 
      // make the new node fixed as well
 
      (new_node_ind[i])->fixed = (div_edges[i].first)->fixed &&
 
	(div_edges[i].second)->fixed;
 

	
 
      // Insert Node into NodeSet if the div_edge is part of it.
 
      if (
 
	  (div_edges[i].first->node_set && div_edges[i].second->node_set) &&
 
	  (div_edges[i].first->node_set == div_edges[i].second->node_set))
 
	{
 
	  //cerr << "Inserting node into node set\n";
 
	  div_edges[i].first->node_set->AddNode( new_node_ind[i] );
 
	}
 

	
 
      // if the new wall should be fixed (i.e. immobile, or moving as
 
      // solid body), make it so, and make it part of the boundary. Using
 
      // this to make a nice initial condition by cutting off part of a
 
      // growing leaf.
 

	
 
      if (fix_cellwall) {
 
	(new_node_ind[i])->fixed = true;
 

	
 
	// All this we'll do later for the node set only
 
      }
 

	
 
      // if new node is inserted into the boundary
 
      // it will be part of the boundary, too
 

	
 
      new_node_ind[i]->UnsetBoundary();
 
      if ((div_edges[i].first->BoundaryP() && div_edges[i].second->BoundaryP()) && // Both edge nodes are boundary nodes AND
 
	  ((m->findNextBoundaryNode(div_edges[i].first))->Index() == div_edges[i].second->Index())){ // The boundary proceeds from first to second.
 

	
 
#ifdef QDEBUG
 
	qDebug() << "Index of the first node: " << div_edges[i].first->Index() << endl;
 
	qDebug() << "Index of the second node: " << div_edges[i].second->Index() << endl;
 
	qDebug() << "Boundary proceeds from: " <<  div_edges[i].first->Index() 
 
		 << "to: " << (m->findNextBoundaryNode(div_edges[i].first))->Index() << endl << endl;
 
#endif
 
	new_node_ind[i]->SetBoundary();
 

	
 
	// We will need to repair the boundary polygon later, since we will insert new nodes
 
	//cerr << "Boundary touched for Node " << new_node_ind[i]->Index() << "\n";
 
	boundary_touched_flag=true;
 

	
 
	// and insert it into the boundary_polygon
 
	// find the position of the first node in the boundary
 
	list<Node *>::iterator ins_pos = find
 
	  (m->boundary_polygon->nodes.begin(),
 
	   m->boundary_polygon->nodes.end(),
 
	   div_edges[i].first);
 
	// ... second node comes before or after it ...
 
	if (*(++ins_pos!=m->boundary_polygon->nodes.end()?
 
	      ins_pos:m->boundary_polygon->nodes.begin())!=div_edges[i].second) {
 

	
 
	  m->boundary_polygon->nodes.insert(((ins_pos--)!=m->boundary_polygon->nodes.begin()?ins_pos:(--m->boundary_polygon->nodes.end())), new_node_ind[i]);
 

	
 
	  // .. set the neighbors of the new node ...
 
	  // in this case e.second and e.first are inverted
 
	} else {
 
	  // insert before second node, so leave ins_pos as it is,
 
	  // that is: incremented
 
	  m->boundary_polygon->nodes.insert(ins_pos, new_node_ind[i]);	
 
	  // .. set the neighbors of the new node ...
 
	}
 
      }
 

	
 
      list<Neighbor> owners;
 

	
 
      // push all cells owning the two nodes of the divides edges
 
      // onto a list
 

	
 
      copy((div_edges[i].first)->owners.begin(),
 
	   (div_edges[i].first)->owners.end(),
 
	   back_inserter(owners));
 
      copy((div_edges[i].second)->owners.begin(),
 
	   (div_edges[i].second)->owners.end(),
 
	   back_inserter(owners));
 

	
 

	
 
      // find first non-self duplicate in the owners: 
 
      // cells owning the same two nodes
 
      // share an edge with me
 
      owners.sort( mem_fun_ref( &Neighbor::Cmp ) );
 

	
 

	
 
#ifdef QDEBUG  
 
      list<Neighbor> unique_owners;
 
      copy(owners.begin(), owners.end(), back_inserter(unique_owners));
 
      unique_owners.unique( mem_fun_ref( &Neighbor::Eq ) );
 
      qDebug() << "The dividing edge nodes: " << div_edges[i].first->Index() 
 
	       << " and " << div_edges[i].second->Index() << " are owned by cells: ";
 

	
 
      // spit out each owners' cell index
 
      foreach(Neighbor neighbor, unique_owners){
 
	qDebug() << neighbor.cell->Index() << "  ";
 
      }
 
      qDebug() << endl;
 
#endif
 

	
 
      // Search through the sorted list of edge node owners looking for duplicate pairs. Each pair represents an actual edge owner.
 
      list<Neighbor> edge_owners;
 
      list<Neighbor>::iterator it;
 
      for (it=owners.begin(); it!=owners.end(); it++) {
 
	it = adjacent_find(it, owners.end(), neighbor_cell_eq);
 
	if (it == owners.end()) break; // bail if reach the end of the list
 
#ifdef QDEBUG
 
	qDebug() << "Considering: " << it->cell->Index() << " as a possible edge owner." << endl;
 
#endif
 
	if (it->cell->Index() != this->Index()) {
 
#ifdef QDEBUG
 
	  qDebug() << "Adding: " << it->cell->Index() << " to the list of edge owners." << endl;
 
#endif
 
	  edge_owners.push_back(*it);
 
	}
 
      } 
 

	
 
      if (edge_owners.size() > 1){
 
	// Remove the boundary polygon - if its there
 
	list<Neighbor>::iterator it;
 
	if ((it = find_if (edge_owners.begin(), edge_owners.end(), bind2nd(mem_fun_ref(&Neighbor::CellEquals), -1)))
 
	    != edge_owners.end()) {
 
#ifdef QDEBUG
 
	  qDebug() << "deleating: " << it->cell->Index() << " from the list of edge owners." << endl;
 
#endif
 
	  edge_owners.erase(it);
 
	}
 
      }
 

	
 
#ifdef QDEBUG
 
      qDebug() << "The edge owners list has: " << edge_owners.size() << " elements" << endl;
 
#endif
 

	
 
      // Since the list should always contain exactly one element, pass it on as an iterator
 
      list<Neighbor>::iterator c = (edge_owners.size() != 0) ? edge_owners.begin() : edge_owners.end();
 

	
 
      // (can we have more than one neighboring cell here??)
 
      if (c!=owners.end()) { 
 
	neighbor_cell = c->cell;
 
	if (!c->cell->BoundaryPolP()) {
 

	
 
	  // find correct position in the cells node list
 
	  // to insert the new node
 
	  list<Node *>::iterator ins_pos = find
 
	    (neighbor_cell->nodes.begin(),
 
	     neighbor_cell->nodes.end(),
 
	     div_edges[i].first);
 

	
 
	  neighbor_cell->nodes.insert(ins_pos, new_node_ind[i]);
 
	  neighbor_cell->ConstructConnections();
 

	
 
	  // give walls to daughter later
 
	}
 
      } else {
 
	neighbor_cell = 0;
 
      }
 
    }
 

	
 
    // Split the Wall with the neighboring cell
 

	
 
    // if the neighbor cell has not yet been identified above, do it now
 
    if (neighbor_cell == 0) {
 

	
 
      list<Neighbor> owners;
 

	
 
      // push all cells owning the two nodes of the divides edges
 
      // onto a list
 
      copy((div_edges[i].first)->owners.begin(),
 
	   (div_edges[i].first)->owners.end(),
 
	   back_inserter(owners));
 
      copy((div_edges[i].second)->owners.begin(),
 
	   (div_edges[i].second)->owners.end(),
 
	   back_inserter(owners));
 

	
 

	
 
      // find first non-self duplicate in the owners: 
 
      // cells owning the same two nodes
 
      // share an edge with me
 
      owners.sort( mem_fun_ref( &Neighbor::Cmp ) );
 

	
 
      list<Neighbor>::iterator c;
 
      for (c=owners.begin(); c!=owners.end(); c++) {
 
	c=adjacent_find(c,owners.end(),neighbor_cell_eq);
 
	if (c->cell->Index() != this->Index() || c==owners.end()) break;
 
      }
 

	
 
      if (c!=owners.end())
 
	neighbor_cell = c->cell;
 
      else 
 
	neighbor_cell = 0;
 
    }
 

	
 

	
 
    if (neighbor_cell /* && !neighbor_cell->BoundaryPolP() */) {
 

	
 
      //cerr << "Cell "  << index << " says: neighboring cell is " << neighbor_cell->index << endl;
 

	
 
      /*************** 1. Find the correct wall element  ********************/
 

	
 
      list<Wall *>::iterator w, start_search;
 
      w = start_search = walls.begin();
 
      do {
 
	// Find wall between this cell and neighbor cell
 
	w = find_if( start_search, walls.end(), bind2nd (mem_fun( &Wall::is_wall_of_cell_p ), neighbor_cell ) );
 
	start_search = w; start_search++; // continue searching at next element
 
      } while ( w!=walls.end() && !(*w)->IntersectsWithDivisionPlaneP( from, to ) ); // go on until we find the right one.
 

	
 
      if (w == walls.end()) {
 
#ifdef QDEBUG
 
	qDebug() << "Whoops, wall element not found...!" << endl;
 
	qDebug() << "Cell ID: " << neighbor_cell->Index() << endl;
 
	qDebug() << "My cell ID: " << Index() << endl;
 
#endif
 
      } else {
 

	
 
	// 2. Split it up, if we should (sometimes, the new node coincides with an existing node so
 
	// we should not split up the Wall)
 

	
 
	if (new_node_ind[i]!=(*w)->n1 && new_node_ind[i]!=(*w)->n2) {
 

	
 
	  Wall *new_wall;
 

	
 
	  // keep the length of the original wall; we need it to equally divide the transporter concentrations
 
	  // over the two daughter walls
 
	  (*w)->SetLength(); // make sure we've got the current length
 
	  orig_length[i] = (*w)->Length();
 
	  //cerr << "Original length is " << orig_length[i] << endl;
 
	  if ((*w)->c1 == this ) {
 

	
 
	    //  cerr << "Cell " << (*w)->c1->Index() << " splits up wall " << *(*w) << ", into: " << endl;
 
	    new_wall = new Wall( (*w)->n1, new_node_ind[i], this, neighbor_cell);
 
	    (*w)->n1 = new_node_ind[i];
 

	
 
	    //  cerr << "wall " << *(*w) << ", and new wall " << *new_wall << endl;
 

	
 
	  } else {
 
	    new_wall = new Wall( (*w)->n1, new_node_ind[i], neighbor_cell, this);
 

	
 
	    (*w)->n1 = new_node_ind[i];
 
	  }
 

	
 

	
 
	  // 3. Give wall elements to appropriate cells
 
	  if (new_wall->n1 != new_wall->n2) {
 

	
 
	    if (par.copy_wall)
 
	      new_wall->CopyWallContents(**w);
 
	    else {
 
	      // If wall contents are not copied, decide randomly which wall will be the "parent"
 
	      // otherwise we will get biases (to the left), for example in the meristem growth model
 
	      if (RANDOM()<0.5) {
 
		new_wall->SwapWallContents(*w);
 
	      }
 
	    }
 
	    AddWall(new_wall);
 
	    // cerr << "Building new wall: this=" << Index() << ", neighbor_cell = " << neighbor_cell->Index() << endl;
 

	
 
	    neighbor_cell->AddWall( new_wall);
 
	    //cerr << "Existing wall: c1 = " << (*w)->c1->Index() << ", neighbor_cell = " << (*w)->c2->Index() << endl;
 

	
 
	    // Remember the addresses of the new walls
 
	    div_wall[2*i+0] = *w;
 
	    div_wall[2*i+1] = new_wall;
 

	
 
	    // we will correct the transporter concentrations later in this member function, after division
 
	    // First the new nodes should be inserted into the cells, before we can calculate wall lengths
 
	    // Remember that cell walls can be bent, so have a bigger length than the Euclidean distance n1->n2
 

	
 
	  } else {
 
	    delete new_wall;
 
	  }
 
	}
 
      }
 
    }
 
  }  // closing loop over the two divided edges (for (int i=0;i<2;i++) )
 

	
 
  // move half of the nodes to the daughter
 
  {
 
    //cerr << "Daughter: ";
 
    list<Node *>::iterator start, stop;
 

	
 
    start=new_node_locations.front();
 

	
 
    //cerr << "*new_node_locations.front() = " << *new_node_locations.front() << endl;
 
    if (new_node_flag[0]==1) {
 
      start++;
 
      if (start==nodes.end())
 
	start=nodes.begin();
 
    }  
 

	
 
    stop=new_node_locations.back();
 
    if (new_node_flag[1]==2) {
 
      if (stop==nodes.begin())
 
	stop=nodes.end();
 
      stop--;
 
    }
 
    list<Node *>::iterator i=start;
 
    while ( i!=stop) {
 

	
 
      // give the node to the daughter
 
      // (find references to parent cell from this node,
 
      // and remove them)
 
      list<Neighbor>::iterator neighb_with_this_cell=
 
	find_if((*i)->owners.begin(),
 
		(*i)->owners.end(),
 
		bind2nd(mem_fun_ref( &Neighbor::CellEquals ),this->Index() )  );
 
      if (neighb_with_this_cell==(*i)->owners.end()) {
 

	
 
#ifdef QDEBUG
 
	qDebug() << "not found" << endl;
 
#endif
 
	abort();
 
      }
 

	
 
      (*i)->owners.erase(neighb_with_this_cell);
 

	
 
      daughter->nodes.push_back( *i );
 

	
 

	
 
      i++;
 
      if (i==nodes.end())
 
	i=nodes.begin();
 
    };
 
  }
 

	
 
  // new node list of parent
 
  list<Node *> new_nodes_parent;
 

	
 
  // half of the nodes stay with the parent
 
  {
 
    list<Node *>::iterator start, stop;
 
    start=new_node_locations.back();
 
    if (new_node_flag[1]==1) {
 
      start++;
 
      if (start==nodes.end())
 
	start=nodes.begin();
 
    }
 
    stop=new_node_locations.front();
 
    if (new_node_flag[0]==2) {
 
      if (stop==nodes.begin())
 
	stop=nodes.end();
 
      stop--;
 
    }
 

	
 
    list<Node *>::iterator i=start;
 
    while (i!=stop) {
 
      new_nodes_parent.push_back( *i );
 

	
 
      i++;
 
      if (i==nodes.end()) 
 
	i = nodes.begin();
 
    };
 
  }
 

	
 
  // insert shared wall
 
  // insert shared nodes on surface of parent cell
 
  new_nodes_parent.push_back( new_node_ind[0] );
 
  daughter->nodes.push_back ( new_node_ind[1] );
 

	
 
  // optionally add the new node to the nodeset (passed by pointer)
 
  // (in this way we can move the NodeSet as a whole; useful for a fixed cutting line)
 
  if (node_set) {
 
    node_set->AddNode( new_node_ind[0] );
 
  }
 

	
 
#define MULTIPLE_NODES
 
#ifdef MULTIPLE_NODES
 
  // intermediate, extra nodes
 
  // Calculate distance between the two new nodes
 
  double dist=( new_node[1] - new_node[0] ).Norm();
 
  //bool fixed_wall = (new_node_ind[0])->fixed && (new_node_ind[1])->fixed;
 
  bool fixed_wall = false;
 

	
 
  // Estimate number of extra nodes in wall
 
  // factor 4 is to keep tension on the walls;
 
  // this is a hidden parameter and should be made explicit
 
  // later on.
 
  int n=(int)((dist/Node::target_length)/4+0.5);
 

	
 
  Vector nodevec = ( new_node[1]- new_node[0]).Normalised();
 

	
 
  double element_length = dist/(double)(n+1);
 

	
 
  // note that wall nodes need to run in inverse order in parent
 
  list<Node *>::iterator ins_pos = daughter->nodes.end();
 
  for (int i=1;i<=n;i++) {
 
    Node *node=
 
      m->AddNode( new Node( new_node[0] + i*element_length*nodevec ) );
 

	
 
    node->fixed=fixed_wall;
 

	
 
    if (!fix_cellwall)
 
      node->boundary = false;
 
    else {
 
      node->fixed = true;
 
    }
 

	
 
    ins_pos=daughter->nodes.insert(ins_pos, node );
 
    new_nodes_parent.push_back( node );
 

	
 
    // optionally add the new node to the nodeset (passed by pointer)
 
    // (in this way we can move the NodeSet as a whole; useful for a fixed cutting line)
 
    if (node_set) {
 
      node_set->AddNode( node );
 
    }
 

	
 
  }
 
#endif
 
  daughter->nodes.push_back( new_node_ind[0] );
 
  new_nodes_parent.push_back( new_node_ind[1] );
 

	
 
  // optionally add the new node to the nodeset (passed by pointer)
 
  // (in this way we can move the NodeSet as a whole; useful for a fixed cutting line)
 
  if (node_set) {
 
    node_set->AddNode( new_node_ind[1] );
 
  }
 

	
 
  // move the new nodes to the parent
 
  nodes.clear();
 
  copy( new_nodes_parent.begin(), 
 
	new_nodes_parent.end(), 
 
	back_inserter(nodes) );
 

	
 

	
 
  // Repair cell lists of Nodes, and node connectivities
 
  ConstructConnections();
 
  daughter->ConstructConnections();
 

	
 
  if (boundary_touched_flag) {
 
    m->boundary_polygon->ConstructConnections();
 
  } 
 

	
 
  // collecting neighbors of divided cell
 
  list<CellBase *> broken_neighbors;
 

	
 
  // this cell's old neighbors
 
  copy(neighbors.begin(), neighbors.end(), back_inserter(broken_neighbors) );
 

	
 
  // this cell
 
  broken_neighbors.push_back(this);
 

	
 
  // its daughter
 
  broken_neighbors.push_back(daughter);
 

	
 
  // Recalculate area of parent and daughter
 
  area = CalcArea();
 
  daughter->area = daughter->CalcArea();
 

	
 
  SetIntegrals();
 
  daughter->SetIntegrals();
 

	
 
  // Add a "Cell Wall" for diffusion algorithms
 
  Wall *wall = new Wall( new_node_ind[0], new_node_ind[1], this, daughter );
 

	
 
  AddWall( wall );
 

	
 
  daughter->AddWall( wall );
 

	
 
  //cerr << "Correct walls of cell " << Index() << " and daughter " << daughter->Index() << endl;
 

	
 
  // Move Walls to daughter cell
 
  list <Wall *> copy_walls = walls;
 
  for (list<Wall *>::iterator w = copy_walls.begin(); w!=copy_walls.end(); w++) {
 

	
 
    //cerr << "Doing wall, before:  " << **w << endl;
 

	
 
    //  checks the nodes of the wall and gives it away if appropriate
 
    (*w)->CorrectWall ( );
 

	
 
    //cerr << "and after: " << **w << endl;
 

	
 
  }
 

	
 
  // Correct tranporterconcentrations of divided walls
 
  for (int i=0;i<4;i++) {
 
    if (div_wall[i]) {
 
      div_wall[i]->SetLength();
 
      div_wall[i]->CorrectTransporters(orig_length[i/2]);
 
    }
 
  }
 

	
 
  //cerr << "Cell " << index << " has been dividing, and gave birth to Cell " << daughter->index << endl;
 

	
 
  // now reconstruct neighbor list for all "broken" neighbors
 

	
 
  for (list<CellBase *>::iterator i=broken_neighbors.begin(); i!=broken_neighbors.end(); i++) {
 
    ((Cell *)(*i))->ConstructNeighborList();
 
  }
 

	
 
  ConstructNeighborList();
 
  daughter->ConstructNeighborList();
 

	
 
  m->plugin->OnDivide(&parent_info, daughter, this);
 

	
 
  daughter->div_counter=(++div_counter);
 
}
 

	
 
// Move the whole cell
 
void Cell::Move(const Vector T) {
 

	
 
  for (list<Node *>::const_iterator i=nodes.begin(); i!=nodes.end(); i++) {
 
    *(*i)+=T;
 
  }
 
}
 

	
 
double Cell::Displace(double dx, double dy, double dh)
 
{
 

	
 
  // Displace whole cell, add resulting energy to dh,
 
  // and accept displacement if energetically favorable
 
  // 
 
  // Method is called if a "fixed" node is displaced
 

	
 
  // Warning: length constraint not yet  CORRECTLY implemented for this function
 

	
 
  // Attempt to move this cell in a random direction
 
  //  Vector movement(par.mc_cell_stepsize*(RANDOM()-0.5),par.mc_cell_stepsize*(RANDOM()-0.5),0);
 

	
 

	
 
  dh=0;
 

	
 
  Vector movement(dx,dy,0);
 

	
 
  vector< pair<Node *, Node *> > length_edges;
 
  vector<double> cellareas;
 
  cellareas.reserve(neighbors.size());
 

	
 
  // for the length constraint, collect all edges to this cell's nodes,
 
  // which are not part of the cell
 
  // the length of these edges will change
 

	
 
  double old_length=0.;
 
  for (list<Node *>::const_iterator i=nodes.begin(); i!=nodes.end(); i++) {
 
    for (list<Neighbor>::const_iterator n=(*i)->owners.begin(); n!=(*i)->owners.end(); n++) {
 
      if (n->getCell()!=this) {
 
	length_edges.push_back( pair <Node *,Node *> (*i, n->nb1) );
 
	length_edges.push_back( pair <Node *,Node *> (*i, n->nb2) );
 
	old_length += 
 
	  DSQR(Node::target_length-(*(*i)-*(n->nb1)).Norm())+
 
	  DSQR(Node::target_length-(*(*i)-*(n->nb2)).Norm());
 
      }
 
    }
 
  }
 

	
 
  // calculate area energy difference of neighboring cells
 
  // (this cells' shape remains unchanged)
 
  double old_area_energy=0., old_length_energy=0.;
 
  for (list<CellBase *>::const_iterator i=neighbors.begin(); i!=neighbors.end(); i++) {
 
    old_area_energy += DSQR((*i)->Area()-(*i)->TargetArea());
 
    old_length_energy += DSQR((*i)->Length()-(*i)->TargetLength());
 
  }
 

	
 
  Move(movement);
 

	
 
  double new_area_energy=0., new_length_energy=0.;
 
  for (list<CellBase *>::const_iterator i=neighbors.begin(); i!=neighbors.end(); i++) {
 
    cellareas.push_back((*i)->CalcArea());
 
    new_area_energy += DSQR(cellareas.back()-(*i)->TargetArea());
 
    new_length_energy += DSQR((*i)->CalcLength()-(*i)->TargetLength());
 
  }
 

	
 
  double new_length=0;
 
  for ( vector< pair< Node *, Node * > >::const_iterator e = length_edges.begin(); e != length_edges.end(); e++) {
 
    new_length +=  DSQR(Node::target_length - (*(e->first) - *(e->second)).Norm());
 
  }
 

	
 

	
 
  dh += (new_area_energy - old_area_energy) + (new_length_energy - old_length_energy) * lambda_celllength +
 
    par.lambda_length * (new_length - old_length);
 

	
 
  if (dh<0 || RANDOM()<exp(-dh/par.T)) {
 

	
 
    // update areas of cells
 
    //cerr << "neighbors: ";
 
    list<CellBase *>::const_iterator nb_it = neighbors.begin();
 
    for (vector<double>::const_iterator ar_it = cellareas.begin(); ar_it!=cellareas.end(); ( ar_it++, nb_it++) ) {
 
      ((Cell *)(*nb_it))->area = *ar_it;
 
      (*nb_it)->SetIntegrals(); 
 
    }
 

	
 
    //cerr << endl;
 

	
 
  } else {
 

	
 
    Move ( -1*movement);
 

	
 
  }
 

	
 
  return dh;
 
}
 

	
 

	
 
void Cell::Displace (void)
 
{
 
  Displace(par.mc_cell_stepsize*(RANDOM()-0.5),par.mc_cell_stepsize*(RANDOM()-0.5),0);
 
}
 

	
 
// Get energy level of whole cell (excluding length constraint?)
 
double Cell::Energy(void) const
 
{
 
  double energy = 0.;
 
  double length_contribution = 0.;
 

	
 
  for (list<Node *>::const_iterator i=nodes.begin(); i!=nodes.end(); i++) {
 
    for (list<Neighbor>::const_iterator n=(*i)->owners.begin(); n!=(*i)->owners.end(); n++) {
 
      if (n->getCell()==this) {
 
	length_contribution += 
 
	  DSQR(Node::target_length-(*(*i)-*(n->nb1)).Norm()) +
 
	  DSQR(Node::target_length-(*(*i)-*(n->nb2)).Norm());
 
      }
 
    }
 
  }
 

	
 
  // wall elasticity constraint
 
  energy += par.lambda_length * length_contribution;
 

	
 
  // area constraint
 
  energy += DSQR(CalcArea() - target_area);
 

	
 
  // cell length constraint
 
  energy += lambda_celllength * DSQR(Length() - target_length);
 

	
 
  return energy;
 
}
 

	
 

	
 

	
 

	
 

	
 
bool Cell::SelfIntersect(void)
 
{
 
  // The (obvious) O(N*N) algorithm
 

	
 
  // Compare each edge against each other edge
 

	
 
  // An O(N log(N)) algorithm by Shamos & Hoey (1976) supposedly exists;
 
  // it was mentioned on comp.graphics.algorithms
 

	
 
  // But I haven't been able to lay my hand on the paper.
 
  // Let's try whether we need it....
 

	
 
  // method used: http://astronomy.swin.edu.au/~pbourke/geometry/lineline2d/
 

	
 
  for (list<Node *>::const_iterator i=nodes.begin(); i!=nodes.end(); i++) {
 

	
 
    list<Node *>::const_iterator j=i; 
 
    ++j;
 
    for (; j!=nodes.end(); j++) 
 
      {
 
	
 
	Vector v1 = *(*i);
 
	list<Node *>::const_iterator nb=i;
 
	nb++;
 
	if (nb == nodes.end()) {
 
	  nb = nodes.begin();
 
	} 
 
	Vector v2 = *(*nb);
 
	Vector v3 = *(*j);
 
	nb=j;
 
	nb++;
 
	if (nb == nodes.end()) {
 
	  nb = nodes.begin();
 
	} 
 
	Vector v4=*( *nb ); 
 

	
 
	double denominator = 
 
	  (v4.y - v3.y)*(v2.x - v1.x) - (v4.x - v3.x)*(v2.y - v1.y);
 

	
 
	double ua = 
 
	  ((v4.x - v3.x)*(v1.y - v3.y) - (v4.y - v3.y)*(v1.x -v3.x))/denominator;
 
	double ub = 
 
	  ((v2.x - v1.x)*(v1.y-v3.y) - (v2.y- v1.y)*(v1.x - v3.x))/denominator;
 

	
 

	
 
	if ( ( TINY < ua && ua < 1.-TINY ) && ( TINY < ub && ub < 1.-TINY ) ) {
 
	  //cerr << "ua = " << ua << ", ub = " << ub << endl;
 
	  return true;
 
	}
 
      }
 
  }
 

	
 
  return false;
 
}
 

	
 

	
 
bool Cell::MoveSelfIntersectsP(Node *moving_node_ind, Vector new_pos)
 
{
 

	
 
  // Check whether the polygon will self-intersect if moving_node_ind 
 
  // were displaced to new_pos
 

	
 
  // Compare the two new edges against each other edge
 

	
 
  // O(2*N)
 

	
 
  // method used for segment intersection:
 
  // http://astronomy.swin.edu.au/~pbourke/geometry/lineline2d/
 

	
 
  Vector neighbor_of_moving_node[2];
 

	
 
  //cerr << "list<Node *>::const_iterator moving_node_ind_pos = find (nodes.begin(),nodes.end(),moving_node_ind);\n";
 
  list<Node *>::const_iterator moving_node_ind_pos = find (nodes.begin(),nodes.end(),moving_node_ind);
 

	
 
  list<Node *>::const_iterator nb = moving_node_ind_pos;
 
  //cerr << "Done\n";
 
  nb++;
 
  if (nb == nodes.end()) {
 
    nb = nodes.begin();
 
  } 
 

	
 
  neighbor_of_moving_node[0]=*(*nb); 
 

	
 
  nb=moving_node_ind_pos;
 
  if (nb == nodes.begin()) {
 
    nb = nodes.end();
 
  }
 
  nb--;
 

	
 
  neighbor_of_moving_node[1]=*( *nb ); 
 

	
 

	
 
  for (list<Node *>::const_iterator i=nodes.begin(); i!=nodes.end(); i++) {
 
    for (int j=0;j<2;j++) { // loop over the two neighbors of moving node
 
      list<Node *>::const_iterator nb=i;
 
      nb++;
 
      if (nb == nodes.end()) {
 
	nb = nodes.begin();
 
      } 
 
      if (*i == moving_node_ind || *nb == moving_node_ind) {
 
	// do not compare to self
 
	continue;
 
      }
 

	
 
      Vector v3 = *(*i);
 
      Vector v4 = *(*nb);
 

	
 
      double denominator = 
 
	(v4.y - v3.y)*(neighbor_of_moving_node[j].x - new_pos.x) - (v4.x - v3.x)*(neighbor_of_moving_node[j].y - new_pos.y);
 

	
 
      double ua = 
 
	((v4.x - v3.x)*(new_pos.y - v3.y) - (v4.y - v3.y)*(new_pos.x -v3.x))/denominator;
 
      double ub = 
 
	((neighbor_of_moving_node[j].x - new_pos.x)*(new_pos.y-v3.y) - (neighbor_of_moving_node[j].y- new_pos.y)*(new_pos.x - v3.x))/denominator;
 

	
 
      if ( ( TINY < ua && ua < 1.-TINY ) && ( TINY < ub && ub < 1.-TINY ) ) {
 
	//cerr << "ua = " << ua << ", ub = " << ub << endl;
 
	return true;
 
      }
 
    }
 
  }
 
  return false;
 
}
 

	
 
/*! \brief Test if this cell intersects with the given line.
 

	
 
 */
 
bool Cell::IntersectsWithLineP(const Vector v1, const Vector v2)
 
{
 
  // Compare the line against each edge
 
  // method used: http://astronomy.swin.edu.au/~pbourke/geometry/lineline2d/
 

	
 
  for (list<Node *>::const_iterator i=nodes.begin(); i!=nodes.end(); i++) 
 
    {
 
      Vector v3 = *(*i);
 
      list<Node *>::const_iterator nb=i;
 
      nb++;
 
      if (nb == nodes.end()) {
 
	nb = nodes.begin();
 
      }
 
      Vector v4 = *(*nb);
 

	
 
      double denominator = 
 
	(v4.y - v3.y)*(v2.x - v1.x) - (v4.x - v3.x)*(v2.y - v1.y);
 

	
 
      double ua = 
 
	((v4.x - v3.x)*(v1.y - v3.y) - (v4.y - v3.y)*(v1.x -v3.x))/denominator;
 
      double ub = 
 
	((v2.x - v1.x)*(v1.y-v3.y) - (v2.y- v1.y)*(v1.x - v3.x))/denominator;
 

	
 
      if ( ( TINY < ua && ua < 1.-TINY ) && ( TINY < ub && ub < 1.-TINY ) ) {
 
	return true;
 
      }
 
    }
 
  return false;
 
}
 
/*! \brief Constructs Walls, but only one per cell boundary.
 

	
 
  Standard method constructs a Wall for each cell wall element,
 
  making transport algorithms computationally more intensive than needed.
 

	
 
  We can remove this? Well, let's leave it in the code in case we need it for something else. E.g. for importing leaf architectures in different formats than our own... :-)
 

	
 
*/
 
void Cell::ConstructWalls(void)
 
{
 
  return;
 
  if (dead) return;
 

	
 
  walls.clear();
 
  neighbors.clear();
 

	
 
  // Get "corner points; i.e. nodes where more than 2 cells are connected
 
  list<Node *> corner_points;
 

	
 
  for (list<Node *>::const_iterator i=nodes.begin(); i!=nodes.end();i++) {
 

	
 
    // look for nodes belonging to >2 cells
 
    if ((*i)->owners.size()>2) {
 

	
 
      // push onto list
 
      corner_points.push_back(*i);
 
    }
 
  }
 

	
 
  // Construct Walls between corner points
 

	
 
  // previous one in list
 
  list<Node *>::const_iterator nb = (--corner_points.end());
 

	
 
  // loop over list, 
 
  for (list<Node *>::const_iterator i=corner_points.begin(); i!=corner_points.end(); ( i++, nb++) ) {
 

	
 
    if (nb==corner_points.end()) nb=corner_points.begin();
 
    // add owning cells to a list
 
    list<Cell *> owning_cells;
 
    Node &n(*(*i));
 

	
 
    for (list<Neighbor>::const_iterator j=n.owners.begin(); j!=n.owners.end(); j++) {
 
      owning_cells.push_back(j->cell);
 
    }
 

	
 
    Node &n2(*(*nb));
 
    for (list<Neighbor>::const_iterator j=n2.owners.begin(); j!=n2.owners.end(); j++) {
 
      owning_cells.push_back(j->cell);
 
    }
 

	
 
    // sort cell owners
 
    owning_cells.sort( mem_fun( &Cell::Cmp ));
 

	
 
    // find duplicates
 
    vector<Cell *> duplicates;
 
    list<Cell *>::const_iterator prevj = (--owning_cells.end());
 
    for (list<Cell *>::const_iterator j=owning_cells.begin(); j!=owning_cells.end(); ( j++, prevj++) ) {
 
      if (prevj==owning_cells.end())
 
	prevj=owning_cells.begin();
 
      if (*j==*prevj) 
 
	duplicates.push_back(*j);
 
    }
 

	
 
    if (duplicates.size()==3) { // ignore cell boundary (this occurs only after the first division, I think)
 
      vector<Cell *>::iterator dup_it = find_if(duplicates.begin(),duplicates.end(),mem_fun(&Cell::BoundaryPolP) );
 
      if (dup_it!=duplicates.end()) 
 
	duplicates.erase(dup_it);
 
      else {
 
	return;
 
      }
 
    }
 

	
 

	
 
    // One Wall for each neighbor, so we should be able to correctly construct neighbor lists here.
 
    if (duplicates[0]==this) {
 
      AddWall(  new Wall(*nb,*i,duplicates[0],duplicates[1]) );
 
      if (!duplicates[1]->BoundaryPolP()) {
 

	
 
	neighbors.push_back(duplicates[1]);
 
      }
 
    } else {
 
      AddWall ( new Wall(*nb,*i,duplicates[1],duplicates[0]) );
 
      if (!duplicates[0]->BoundaryPolP()) {
 
	neighbors.push_back(duplicates[0]);
 

	
 
      }
 
    }
 
  }
 
}
 

	
 

	
 
void BoundaryPolygon::Draw(QGraphicsScene *c, QString tooltip)
 
{
 

	
 
  // Draw the BoundaryPolygon on a QCanvas object
 

	
 
  CellItem* p = new CellItem(this, c);
 

	
 
  QPolygonF pa(nodes.size());
 
  int cc=0;
 

	
 
  for (list<Node *>::const_iterator n=nodes.begin(); n!=nodes.end(); n++) {
 
    Node *i=*n;
 
    pa[cc++] = QPoint((int)((Offset().x+i->x)*Factor()), (int)((Offset().y+i->y)*Factor()) );
 
  }
 

	
 
  p->setPolygon(pa);
 
  p->setPen(par.outlinewidth>=0?QPen( QColor(par.cell_outline_color),par.outlinewidth):QPen(Qt::NoPen));
 
  p->setBrush( Qt::NoBrush );
 
  p->setZValue(1);
 

	
 
  if (!tooltip.isEmpty())
 
    p->setToolTip(tooltip);
 

	
 
  p->show();
 
}
 

	
 
void Cell::Flux(double *flux, double *D)
 
{
 
  // loop over cell edges
 

	
 
  for (int c=0;c<NChem();c++)
 
    flux[c]=0.;
 

	
 
  for (list<Wall *>::iterator i=walls.begin(); i!=walls.end(); i++) {
 

	
 
    // leaf cannot take up chemicals from environment ("no flux boundary")
 
    if ((*i)->c2->BoundaryPolP()) continue;
 

	
 

	
 
    // flux depends on edge length and concentration difference
 
    for (int c=0;c<NChem();c++) {
 
      double phi = (*i)->length * ( D[c] ) * ( ((Cell *)(*i)->c2)->chem[c] - chem[c] );
 

	
 
#ifdef QDEBUG
 
      if ((*i)->c1!=this) {
 
	qDebug() << "Warning, bad cells boundary: " << (*i)->c1->Index() << ", " << index << endl;
 
      }
 
#endif
 

	
 
      flux[c] += phi;
 
    }    
 
  }
 
}
 

	
 

	
 
// graphics stuff, not compiled for batch versions
 
#ifdef QTGRAPHICS
 

	
 
#include "canvas.h"
 

	
 
void Cell::Draw(QGraphicsScene *c, QString tooltip)
 
{
 

	
 
  // Draw the cell on a QCanvas object
 

	
 
  if (DeadP()) { 
 
#ifdef QDEBUG
 
    qDebug() << "Cell " << index << " not drawn, because dead." << endl;
 
#endif
 
    return;
 
  }
 

	
 
  CellItem* p = new CellItem(this, c);
 

	
 
  QPolygonF pa(nodes.size());
 
  int cc=0;
 

	
 
  for (list<Node *>::const_iterator n=nodes.begin(); n!=nodes.end(); n++) {
 
    Node *i=*n;
 

	
 
    pa[cc++] = QPoint((int)((offset[0]+i->x)*factor),
 
		      (int)((offset[1]+i->y)*factor) );
 
  }
 

	
 

	
 
  QColor cell_color;
 

	
 
  m->plugin->SetCellColor(this,&cell_color);
 

	
 
  p->setPolygon(pa);
 
  p->setPen(par.outlinewidth>=0?QPen( QColor(par.cell_outline_color),par.outlinewidth):QPen(Qt::NoPen));
 
  p->setBrush( cell_color );
 
  p->setZValue(1);
 

	
 
  if (!tooltip.isEmpty())
 
    p->setToolTip(tooltip);
 

	
 
  p->show();
 
}
 

	
 

	
 
void Cell::DrawCenter(QGraphicsScene *c) const {
 
  // Maginfication derived similarly to that in nodeitem.cpp
 
  // Why not use Cell::Magnification()?
 
  const double mag = par.node_mag;
 

	
 
  // construct an ellipse
 
  QGraphicsEllipseItem *disk = new QGraphicsEllipseItem ( -1*mag, -1*mag, 2*mag, 2*mag, 0, c );
 
  disk->setBrush( QColor("forest green") );
 
  disk->setZValue(5);
 
  disk->show();
 
  Vector centroid=Centroid();
 
  disk -> setPos((offset[0]+centroid.x)*factor,(offset[1]+centroid.y)*factor);
 
}
 

	
 
void Cell::DrawNodes(QGraphicsScene *c) const {
 

	
 
  for (list<Node *>::const_iterator n=nodes.begin(); n!=nodes.end(); n++) {
 
    Node *i=*n;
 

	
 
    NodeItem *item = new NodeItem ( &(*i), c );
 
    item->setColor();
 
    item->setZValue(5);
 
    item->show();
 
    item ->setPos(((offset[0]+i->x)*factor), ((offset[1]+i->y)*factor) );
 
  }
 
}
 

	
 
void Cell::DrawIndex(QGraphicsScene *c) const {
 

	
 
  DrawText( c, QString("%1").arg(index));
 
}
 

	
 
// Draw any text in the cell's center
 
void Cell::DrawText(QGraphicsScene *c, const QString &text) const {
 

	
 
  Vector centroid = Centroid();
 
  QGraphicsSimpleTextItem *ctext = new QGraphicsSimpleTextItem ( text, 0, c );
 
  ctext->setPen( QPen(QColor(par.textcolor)) );
 
  ctext->setZValue(20);
 
  ctext->setFont( QFont( "Helvetica", par.cellnumsize, QFont::Bold) );
 
  ctext->show();
 
  ctext ->setPos(((offset[0]+centroid.x)*factor),
 
		 ((offset[1]+centroid.y)*factor) );
 
}
 

	
 

	
 
void Cell::DrawAxis(QGraphicsScene *c) const {
 

	
 
  Vector long_axis;
 
  double width;
 
  Length(&long_axis, &width);
 

	
 
  //cerr << "Length is "  << length << endl;
 
  long_axis.Normalise();
 
  Vector short_axis=long_axis.Perp2D();
 

	
 

	
 
  Vector centroid = Centroid();
 
  Vector from = centroid - 0.5 * width * short_axis;
 
  Vector to = centroid + 0.5 * width *short_axis;
 

	
 

	
 
  QGraphicsLineItem *line = new QGraphicsLineItem(0, c);
 
  line->setPen( QPen(QColor(par.arrowcolor),2) );
 
  line->setZValue(2);
 

	
 
  line->setLine( ( (offset[0]+from.x)*factor ),
src/cell.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  This file is part of the Virtual Leaf.
 
 *
 
 *  The Virtual Leaf is free software: you can redistribute it and/or modify
 
 *  VirtualLeaf 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,
 
 *  VirtualLeaf 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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#ifndef _CELL_H_
 
#define _CELL_H_
 

	
 
#include <list>
 
#include <vector>
 
#include <iostream>
 
#include <QString>
 
#include "vector.h"
 
#include "parameter.h"
 
#include "wall.h"
 
#include "warning.h"
 
#include "cellbase.h"
 
#include "cell.h"
 

	
 
#include <QGraphicsScene>
 
#include <qcolor.h>
 
#include <QObject>
 

	
 
#include <libxml/parser.h>
 
#include <libxml/tree.h>
 
#include <QMouseEvent>
 

	
 
class Cell : public CellBase 
 
{
 

	
 
  Q_OBJECT
 
    friend class Mesh;
 
  friend class FigureEditor;
 

	
 
 public:
 
  Cell(double x, double y, double z = 0.);
 
  Cell(void);
 
  Cell(const Cell &src);
 
  Cell operator=(const Cell &src);
 
  bool Cmp(Cell*) const;
 
  bool Eq(Cell*) const;
 

	
 
  inline bool IndexEquals(int i) { return i == index; }
 

	
 
  static void SetMagnification(const double &magn) {
 
    factor=magn;
 
  }
 
  static Vector Offset(void) {
 
    Vector offs;
 
    offs.x=offset[0];
 
    offs.y=offset[1];
 
    return offs;
 
  }
 

	
 
  static void Translate(const double &tx,const double &ty) {
 
    offset[0]+=tx;
 
    offset[1]+=ty;
 
  }
 

	
 
  inline static double Factor(void) {
 
    return factor;
 
  }
 
  static void setOffset(double ox, double oy) {
 
    offset[0]=ox;
 
    offset[1]=oy;
 
  }
 
  static double Magnification(void) {
 
    return factor;
 
  }
 

	
 
  static double Scale(const double scale) {
 
    factor*=scale;
 
    return factor;
 
  }
 

	
 
  void DivideOverAxis(Vector axis); // divide cell over axis
 

	
 
  // divide over the line (if line and cell intersect)
 
  bool DivideOverGivenLine(const Vector v1, const Vector v2, bool wall_fixed = false, NodeSet *node_set = 0);
 

	
 
  void Divide(void) { // Divide cell over short axis
 

	
 
    Vector long_axis; 
 
    Length(&long_axis); 
 
    DivideOverAxis(long_axis.Perp2D()); 
 
  }
 

	
 
  //void CheckForGFDrivenDivision(void);
 
  inline int NNodes(void) const { return nodes.size(); }
 

	
 
  void Move(Vector T);
 
  void Move(double dx, double dy, double dz=0) {
 
    Move( Vector (dx, dy, dz) );
 
  }
 

	
 
  double Displace(double dx, double dy, double dh);
 
  void Displace(void);
 
  double Energy(void) const;
 
  bool SelfIntersect(void);
 
  bool MoveSelfIntersectsP(Node *nid, Vector new_pos);
 
  bool IntersectsWithLineP(const Vector v1, const Vector v2);
 

	
 
  void XMLAdd(xmlNodePtr cells_node) const;
 

	
 
  void ConstructWalls(void);
 
  void Flux(double *flux, double *D);
 

	
 
  void OnClick(QMouseEvent *e);
 
  inline Mesh& getMesh(void) const { return *m; }
 
  double MeanArea(void);
 

	
 
  void Apoptose(void); // Cell kills itself
 
  list<Wall *>::iterator RemoveWall( Wall *w );
 
  void AddWall( Wall *w );
 

	
 
  void Draw(QGraphicsScene *c, QString tooltip = QString::Null());
 

	
 
  // Draw a text in the cell's center
 
  void DrawText(QGraphicsScene *c, const QString &text) const;
 
  void DrawIndex(QGraphicsScene *c) const;
 
  void DrawCenter(QGraphicsScene *c) const;
 
  void DrawNodes(QGraphicsScene *c) const;
 

	
 
  void DrawAxis(QGraphicsScene *c) const;
 
  void DrawStrain(QGraphicsScene *c) const;
 
  void DrawFluxes(QGraphicsScene *c, double arrowsize = 1.);
 
  void DrawWalls(QGraphicsScene *c) const;
 
  void DrawValence(QGraphicsScene *c) const;
 
  void EmitValues(double t);
 

	
 
 signals:
 
  void ChemMonValue(double t, double *x);
 

	
 
 protected:
 
  void XMLAddCore(xmlNodePtr xmlcell) const;
 
  int XMLRead(xmlNode *cur);
 
  void DivideWalls(ItList new_node_locations, const Vector from, const Vector to, bool wall_fixed = false, NodeSet *node_set = 0);
 

	
 
 private:
 

	
 
  static QPen *cell_outline_pen;
 
  static double offset[3];
 
  static double factor;
 
  Mesh *m;
 
  void ConstructConnections(void);
 
  void SetWallLengths(void);
 
};
 

	
 

	
 
// Boundarypolygon is a special cell; will not increase ncells
 
//  and will not be part of Mesh::cells
 
class BoundaryPolygon : public Cell {
 

	
 
 public:
 
 BoundaryPolygon(void) : Cell() {
 
    NCells()--;
 
    index=-1;
 
  }
 

	
 
 BoundaryPolygon(double x,double y,double z=0) : Cell (x,y,z) {
 
    NCells()--;
 
    index=-1;
 
  }
 

	
 
  BoundaryPolygon &operator=(Cell &src) {
 
    Cell::operator=(src);
 
    index=-1;
 
    return *this;
 
  }
 
  virtual void Draw(QGraphicsScene *c, QString tooltip = QString::Null());
 

	
 
  virtual void XMLAdd(xmlNodePtr parent_node) const;
 

	
 
  virtual bool BoundaryPolP(void) const { return true; } 
 
};
 

	
 
#endif
 

	
 
/* finis */
src/cellbase.cpp
Show inline comments
 
/*
 
 *
 
 *  This file is part of the Virtual Leaf.
 
 *
 
 *  The Virtual Leaf is free software: you can redistribute it and/or modify
 
 *  VirtualLeaf 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,
 
 *  VirtualLeaf 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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include <cmath>
 
#include <string>
 
#include <sstream>
 
#include <vector>
 
#include <algorithm>
 
#include <functional>
 
#ifdef QTGRAPHICS
 
#include <QGraphicsScene>
 
#include <qpainter.h>
 
#include <qcolor.h>
 
#include <qfont.h>
 
#include <qwidget.h>
 
//Added by qt3to4:
 
#include <Q3PointArray>
 
#include <fstream>
 
#include "nodeitem.h"
 
#include "cellitem.h"
 
#include "qcanvasarrow.h"
 
#endif
 
#include "nodeset.h"
 

	
 
#include "cellbase.h"
 
#include "wall.h"
 
#include "random.h"
 
#include "parameter.h" 
 
#include "mesh.h"
 
#include "sqr.h"
 
#include "tiny.h"
 

	
 
static const std::string _module_id("$Id$");
 

	
 
extern Parameter par;
 

	
 
const char* CellBase::boundary_type_names[4] = {"None", "NoFlux", "SourceSink", "SAM"};
 

	
 
#ifndef VLEAFPLUGIN
 
CellsStaticDatamembers *CellBase::static_data_members = new CellsStaticDatamembers();
 
#else
 
CellsStaticDatamembers *CellBase::static_data_members = 0;
 
#endif
 

	
 
CellBase::CellBase(QObject *parent) : 
 
  QObject(parent),
 
  Vector()
 
{
 

	
 
  chem=new double[NChem()];
 
  for (int i=0;i<NChem();i++) {
 
    chem[i]=0.;
 
  }
 
  new_chem=new double[NChem()];
 
  for (int i=0;i<NChem();i++) {
 
    new_chem[i]=0.;
 
  }
 
  boundary=None;
 
  index=(NCells()++);
 
  area=0.;
 
  target_area=1;
 
  target_length=0; //par.target_length;
 
  lambda_celllength = 0; //par.lambda_celllength;
 
  intgrl_xx=0.; intgrl_xy=0.; intgrl_yy=0.;
 
  intgrl_x=0.; intgrl_y=0.;
 
  source = false;
 
  source_conc = 0.;
 
  source_chem = 0;
 
  at_boundary=false;
 
  fixed = false;
 
  pin_fixed = false;
 
  stiffness = 0;
 
  marked = false;
 
  dead = false;
 
  div_counter=0;
 
  cell_type = 0;
 
  flag_for_divide = false;
 
  division_axis = 0;
 
}
 

	
 

	
 
CellBase::CellBase(double x,double y,double z) : QObject(), Vector(x,y,z)
 
{
 
#ifndef VLEAFPLUGIN
 
  if (static_data_members == 0) {
 
    static_data_members = new CellsStaticDatamembers();
 
  }
 
#endif
 
  chem=new double[NChem()];
 
  for (int i=0;i<NChem();i++) {
 
    chem[i]=0.;
 
  }
 
  new_chem=new double[NChem()];
 
  for (int i=0;i<NChem();i++) {
 
    new_chem[i]=0.;
 
  }
 
  boundary=None;
 
  area=0.;
 
  target_area=1;
 
  target_length=0; //par.target_length;
 
  lambda_celllength=0; // par.lambda_celllength;
 

	
 
  index=(NCells()++);
 

	
 
  intgrl_xx=0.; intgrl_xy=0.; intgrl_yy=0.;
 
  intgrl_x=0.; intgrl_y=0.;
 

	
 
  source = false;
 
  fixed = false;
 
  at_boundary=false;
 
  pin_fixed = false;
 
  stiffness = 0;
 
  marked=false;
 
  dead  = false;
 
  div_counter = 0;
 
  cell_type = 0;
 
  flag_for_divide = false;
 
  division_axis = 0;
 
}
 

	
 
CellBase::CellBase(const CellBase &src) :  Vector(src), QObject()
 
CellBase::CellBase(const CellBase &src) :  QObject(), Vector(src)
 
{
 

	
 
  chem=new double[NChem()];
 
  for (int i=0;i<NChem();i++) {
 
    chem[i]=src.chem[i];
 
  }
 
  new_chem=new double[NChem()];
 
  for (int i=0;i<NChem();i++) {
 
    new_chem[i]=src.new_chem[i];
 
  }
 
  boundary=src.boundary;
 
  area=src.area;
 
  target_length=src.target_length;
 
  lambda_celllength=src.lambda_celllength;
 

	
 
  intgrl_xx=src.intgrl_xx; intgrl_xy=src.intgrl_xy; intgrl_yy=src.intgrl_yy;
 
  intgrl_x=src.intgrl_x; intgrl_y=src.intgrl_y;
 

	
 
  target_area=src.target_area;
 
  index=src.index;
 
  nodes=src.nodes;
 
  neighbors=src.neighbors;
 
  walls=src.walls;
 
  source = src.source;
 
  fixed = src.fixed;
 
  source_conc = src.source_conc;
 
  source_chem = src.source_chem;
 
  cellvec = src.cellvec;
 
  at_boundary=src.at_boundary;
 
  pin_fixed = src.pin_fixed;
 
  stiffness = src.stiffness;
 
  marked = src.marked;
 
  dead = src.dead;
 
  cell_type = src.cell_type;
 
  div_counter = src.div_counter;
 
  flag_for_divide = src.flag_for_divide;
 
  division_axis = src.division_axis;
 
}
 

	
 

	
 
CellBase CellBase::operator=(const CellBase &src)
 
{
 
  Vector::operator=(src);
 

	
 
  for (int i=0;i<NChem();i++) {
 
    chem[i]=src.chem[i];
 
  }
 
  for (int i=0;i<NChem();i++) {
 
    new_chem[i]=src.chem[i];
 
  }
 
  boundary=src.boundary;
 
  area=src.area;
 
  intgrl_xx=src.intgrl_xx; intgrl_xy=src.intgrl_xy; intgrl_yy=src.intgrl_yy;
 
  intgrl_x=src.intgrl_x; intgrl_y=src.intgrl_y;
 
  target_area=src.target_area;
 
  target_length=src.target_length;
 
  lambda_celllength=src.lambda_celllength;
 

	
 
  index=src.index;
 

	
 
  nodes=src.nodes;
 
  neighbors=src.neighbors;
 
  walls=src.walls;
 
  source = src.source;
 
  fixed = src.fixed;
 
  source_conc = src.source_conc;
 
  source_chem = src.source_chem;
 
  cellvec = src.cellvec;
 
  at_boundary=src.at_boundary;
 
  pin_fixed = src.pin_fixed;
 
  stiffness = src.stiffness;
 
  marked = src.marked;
 
  dead = src.dead;
 
  cell_type = src.cell_type;
 
  div_counter = src.div_counter;
 
  flag_for_divide = src.flag_for_divide;
 
  division_axis = src.division_axis;
 
  return *this;
 
}
 

	
 
void CellBase::SetChemical(int c, double conc)
 
{
 
  if (c>=NChem()) {
 
    stringstream error;
 
    error << "SetChemical: value c = " << c << " is out of range\n";
 
    throw error.str().c_str();
 
  }
 
  chem[c]=conc;
 
}
 

	
 
void CellBase::SetTransporters(int ch, double conc)
 
{
 
  if (ch>=NChem()) {
 
    stringstream error;
 
    error << "SetChemical: value ch = " << ch << " is out of range\n";
 
    throw error.str().c_str();
 
  }
 
  for (list<Wall *>::iterator w=walls.begin(); w!=walls.end(); w++) {
 
    (*w)->setTransporter(this, ch, conc);
 
  }
 
}
 

	
 
ostream &CellBase::print(ostream &os) const
 
{
 

	
 

	
 
  os << "[ index = " << index << " {" << x << ", " << y << ", " << z << "}: {";
 

	
 
  for (int i=0;i<NChem()-1;i++) {
 
    os << chem[i] << ", ";
 
  }
 

	
 
  os << chem[NChem()-1] << " } ]";
 

	
 
  os << endl << "Nodelist = { " << endl;
 

	
 
  for (list<Node *>::const_iterator i =  nodes.begin(); i!=nodes.end(); i++) {
 
    os << (*i)->Index() << "( " << *i << ") ";
 
  }
 
  os << " } ";
 

	
 
  for (list<Wall *>::const_iterator i =  walls.begin(); i!=walls.end(); i++) {
 
    (*i)->print(os);
 
    os << ", ";
 
  } 
 
  os << endl;
 

	
 
  os << " [ area = " << area << " ]";
 
  os << " [ walls = ";
 

	
 
  for (list<Wall *>::const_iterator i= walls.begin(); i!=walls.end(); i++) {
 
    os << (*i)->n1->Index() << " -> " << (*i)->n2->Index() << ", " <<  (*i)->c1->Index() << " | " << (*i)->c2->Index() << ", ";
 
  }
 
  os << " ] ";
 
  os << "div_counter = " << div_counter << endl;
 
  os << "cell_type = " << cell_type << endl;
 
  os << endl;
 
  return os;
 
}
 

	
 
ostream &operator<<(ostream &os, const CellBase &c)
 
{
 
  c.print(os);
 
  return os;
 
}
 

	
 

	
 
double CellBase::CalcArea(void) const
 
{
 

	
 
  double loc_area=0.;
 

	
 
  for (list<Node *>::const_iterator i=nodes.begin(); i!=(nodes.end()); i++) {
 

	
 
    list<Node *>::const_iterator i_plus_1=i; i_plus_1++;
 
    if (i_plus_1==nodes.end())
 
      i_plus_1=nodes.begin();
 

	
 
    loc_area+= (*i)->x * (*i_plus_1)->y;
 
    loc_area-= (*i_plus_1)->x * (*i)->y;
 
  }
 

	
 
  // http://technology.niagarac.on.ca/courses/ctec1335/docs/arrays2.pdf	
 
  return fabs(loc_area)/2.0; 
 
} 
 

	
 
Vector CellBase::Centroid(void) const
 
{
 

	
 
  double area=0.;
 
  double integral_x_dxdy=0.,integral_y_dxdy=0.;
 

	
 
  for (list<Node *>::const_iterator i=nodes.begin(); i!=(nodes.end()); i++) {
 

	
 
    list<Node *>::const_iterator i_plus_1=i; i_plus_1++;
 
    if (i_plus_1==nodes.end())
 
      i_plus_1=nodes.begin();
 

	
 
    area+= (*i)->x * (*i_plus_1)->y;
 
    area-= (*i_plus_1)->x * (*i)->y;
 

	
 
    integral_x_dxdy+=
 
      ((*i_plus_1)->x+(*i)->x)*
 
      ((*i)->x*(*i_plus_1)->y-
 
       (*i_plus_1)->x*(*i)->y);
 
    integral_y_dxdy+=
 
      ((*i_plus_1)->y+(*i)->y)*
 
      ((*i)->x*(*i_plus_1)->y-
 
       (*i_plus_1)->x*(*i)->y);
 
  }
 

	
 
  area = fabs(area)/2.0;
 

	
 
  integral_x_dxdy/=6.;
 
  integral_y_dxdy/=6.;
 

	
 
  Vector centroid(integral_x_dxdy,integral_y_dxdy,0);
 
  centroid/=area;
 
  return centroid;
 
}
 

	
 

	
 

	
 
void CellBase::SetIntegrals(void) const
 
{
 

	
 
  // Set the initial values for the integrals over x^2,
 
  // xy, yy, x, and y
 

	
 
  // these values will be updated after each move of the CellBase wall
 

	
 
  intgrl_xx=0.; intgrl_xy=0.; intgrl_yy=0.;
 
  intgrl_x=0.; intgrl_y=0.;
 
  area=0.;
 
  list<Node *>::const_iterator nb;
 
  list<Node *>::const_iterator i=nodes.begin();
 

	
 
  for (; i!=(nodes.end()); i++) {
 

	
 
    nb = i; nb++; if (nb==nodes.end()) nb=nodes.begin();
 

	
 
    area+=(*i)->x*(*nb)->y;
 
    area-=(*nb)->x*(*i)->y;
 
    intgrl_xx+= 
 
      ((*i)->x*(*i)->x+
 
       (*nb)->x*(*i)->x+
 
       (*nb)->x*(*nb)->x ) *
 
      ((*i)->x*(*nb)->y-
 
       (*nb)->x*(*i)->y);
 
    intgrl_xy+= 
 
      ((*nb)->x*(*i)->y-
 
       (*i)->x*(*nb)->y)*
 
      ((*i)->x*(2*(*i)->y+(*nb)->y)+
 
       (*nb)->x*((*i)->y+2*(*nb)->y));
 
    intgrl_yy+=
 
      ((*i)->x*(*nb)->y-
 
       (*nb)->x*(*i)->y)*
 
      ((*i)->y*(*i)->y+
 
       (*nb)->y*(*i)->y+
 
       (*nb)->y*(*nb)->y );
 
    intgrl_x+=
 
      ((*nb)->x+(*i)->x)*
 
      ((*i)->x*(*nb)->y-
 
       (*nb)->x*(*i)->y);
 
    intgrl_y+=
 
      ((*nb)->y+(*i)->y)*
 
      ((*i)->x*(*nb)->y-
 
       (*nb)->x*(*i)->y);
 
  }
 
  area = fabs(area)/2.0;
 
}
 

	
 
double CellBase::Length(Vector *long_axis, double *width)  const
 
{
 

	
 
  // Calculate length and axes of CellBase
 

	
 
  // Calculate inertia tensor
 
  // see file inertiatensor.nb for explanation of this method
 
  if (!lambda_celllength) {
 

	
 
    // Without length constraint we do not keep track of the cells'
 
    // moments of inertia. So we must calculate them here.
 
    SetIntegrals();
 
  }
 

	
 
  double intrx=intgrl_x/6.;
 
  double intry=intgrl_y/6.;
 
  double ixx=(intgrl_xx/12.)-(intrx*intrx)/area;
 
  double ixy=(intgrl_xy/24.)+(intrx*intry)/area;
 
  double iyy=(intgrl_yy/12.)-(intry*intry)/area;
 

	
 
  double rhs1=(ixx+iyy)/2., rhs2=sqrt( (ixx-iyy)*(ixx-iyy)+4*ixy*ixy )/2.;
 

	
 
  double lambda_b=rhs1+rhs2;
 

	
 
  // see: http://scienceworld.wolfram.com/physics/MomentofInertiaEllipse.html
 
  //    cerr << "n = " << n << "\n";
 

	
 
  if (long_axis) {
 
    *long_axis = Vector(-ixy, lambda_b - ixx, 0);
 
    //   cerr << "ixx = " << ixx << ", ixy = " << ixy << ", iyy = " << iyy << ", area = " << area << endl;
 
  }
 

	
 
  if (width) {
 
    *width = 4*sqrt((rhs1-rhs2)/area);
 
  }
 

	
 
  return 4*sqrt(lambda_b/area);
 
}
 

	
 
double CellBase::CalcLength(Vector *long_axis, double *width)  const
 
{
 

	
 
  // Calculate length and axes of CellBase, without touching cells raw moments
 

	
 
  // Calculate inertia tensor
 
  // see file inertiatensor.nb for explanation of this method
 

	
 
  double my_intgrl_xx=0., my_intgrl_xy=0., my_intgrl_yy=0.;
 
  double my_intgrl_x=0., my_intgrl_y=0., my_area=0.;
 
  my_area=0.;
 
  list<Node *>::const_iterator nb;
 
  list<Node *>::const_iterator i=nodes.begin();
 

	
 
  for (; i!=(nodes.end()); i++) {
 

	
 
    nb = i; nb++; if (nb==nodes.end()) nb=nodes.begin();
 

	
 
    my_area+=(*i)->x*(*nb)->y;
 
    my_area-=(*nb)->x*(*i)->y;
 
    my_intgrl_xx+= 
 
      ((*i)->x*(*i)->x+
 
       (*nb)->x*(*i)->x+
 
       (*nb)->x*(*nb)->x ) *
 
      ((*i)->x*(*nb)->y-
 
       (*nb)->x*(*i)->y);
 
    my_intgrl_xy+= 
 
      ((*nb)->x*(*i)->y-
 
       (*i)->x*(*nb)->y)*
 
      ((*i)->x*(2*(*i)->y+(*nb)->y)+
 
       (*nb)->x*((*i)->y+2*(*nb)->y));
 
    my_intgrl_yy+=
 
      ((*i)->x*(*nb)->y-
 
       (*nb)->x*(*i)->y)*
 
      ((*i)->y*(*i)->y+
 
       (*nb)->y*(*i)->y+
 
       (*nb)->y*(*nb)->y );
 
    my_intgrl_x+=
 
      ((*nb)->x+(*i)->x)*
 
      ((*i)->x*(*nb)->y-
 
       (*nb)->x*(*i)->y);
 
    my_intgrl_y+=
 
      ((*nb)->y+(*i)->y)*
 
      ((*i)->x*(*nb)->y-
 
       (*nb)->x*(*i)->y);
 
  }
 

	
 

	
 
  //my_area/=2.0;
 
  my_area = fabs(my_area)/2.0;
 

	
 

	
 
  double intrx=my_intgrl_x/6.;
 
  double intry=my_intgrl_y/6.;
 
  double ixx=(my_intgrl_xx/12.)-(intrx*intrx)/my_area;
 
  double ixy=(my_intgrl_xy/24.)+(intrx*intry)/my_area;
 
  double iyy=(my_intgrl_yy/12.)-(intry*intry)/my_area;
 

	
 
  double rhs1=(ixx+iyy)/2., rhs2=sqrt( (ixx-iyy)*(ixx-iyy)+4*ixy*ixy )/2.;
 

	
 
  double lambda_b=rhs1+rhs2;
 

	
 
  // see: http://scienceworld.wolfram.com/physics/MomentofInertiaEllipse.html
 
  //    cerr << "n = " << n << "\n";
 

	
 
  if (long_axis) {
 
    *long_axis = Vector(-ixy, lambda_b - ixx, 0);
 
    //   cerr << "ixx = " << ixx << ", ixy = " << ixy << ", iyy = " << iyy << ", my_area = " << my_area << endl;
 
  }
 

	
 
  if (width) {
 
    *width = 4*sqrt((rhs1-rhs2)/my_area);
 
  }
 

	
 
  return 4*sqrt(lambda_b/my_area);
 
}
 

	
 

	
 
void CellBase::ConstructNeighborList(void)
 
{
 

	
 
  neighbors.clear();
 
  for (//list<Wall *>::const_reverse_iterator wit=walls.rbegin();
 
       list<Wall *>::const_iterator wit=walls.begin();
 
       // somehow the reverse_iterator returns by walls needs to be casted to const to let this work.
 
       // it seems to me it is a bug in the STL implementation...
 

	
 
       wit!=walls.end();
 
       wit++) {
 

	
 
    if ((*wit)->C1() != this) {
 
      neighbors.push_back((*wit)->C1());
 
    } else {
 
      neighbors.push_back((*wit)->C2());
 
    }
 

	
 
  }
 

	
 

	
 
  // remove all boundary_polygons from the list
 
  list <CellBase *>::iterator e=neighbors.begin();
 
  at_boundary=false;
 

	
 
  do { 
 
    // Code crashes here after cutting off part of the leaf. I can't find the problem.
 
    // Leaving the "Illegal" walls in the simulation helps. (c1=-1 && c2=-1)
 
    // Work-around: define leaf primordium. Save to XML. Restart. Read XML file.
 
    // Sorry about this; I hope to solve this annoying issue later. RM :-).
 
    // All cells in neighbors seem to be okay (I might be messing some part of the memory elsewhere
 
    // during the cutting operation?).
 
    e = find_if(neighbors.begin(),neighbors.end(),mem_fun(&CellBase::BoundaryPolP));
 
    if (e!=neighbors.end()) {
 
      e=neighbors.erase(e);
 
      at_boundary=true;
 
    } else {
 
      break;
 
    }
 
  } while(1);
 
}
 

	
 
// Save the cell to a stream so we can reconstruct its state later
 
void CellBase::Dump(ostream &os) const
 
{
 

	
 

	
 
  os << index << " " << nodes.size() << endl;
 

	
 
  Vector::Dump(os);
 
  os << endl;
 

	
 
  for (list<Node *>::const_iterator i=nodes.begin();i!=nodes.end();i++) {
 
    os << *i << " ";
 
  }
 
  os << endl;
 

	
 

	
 
  os << index << " " << neighbors.size() << endl;
 
  for (list<CellBase *>::const_iterator i=neighbors.begin();i!=neighbors.end();i++) {
 
    os << *i << " ";
 
  }
 

	
 
  os << endl << walls.size() << endl << endl;
 
  os << NChem() << " ";
 

	
 
  for (int i=0;i<NChem();i++) {
 
    os << chem[i] << " ";
 
  }
 
  os << endl;
 

	
 
  os << NChem() << " ";
 
  for (int i=0;i<NChem();i++) {
 
    os << new_chem[i] << " ";
 
  }
 
  os << endl;
 

	
 
  os << boundary << " " << area << " " << target_area << " " << target_length 
 
     << " " << fixed << " " << intgrl_xx << " " << intgrl_xy << " " << intgrl_yy 
 
     << " " << intgrl_x << " " << intgrl_y << " " << source << " ";
 

	
 
  cellvec.Dump(os);
 

	
 
  os << " " << source_conc << " " << source_chem;
 
  os << endl;
 
}
 

	
 

	
 
void CellBase::UnfixNodes(void)
 
{
 
  for (list<Node *>::const_iterator i=nodes.begin(); i!=nodes.end(); i++) {
 
    (*i)->Unfix();
 
  }
 
}
 

	
 

	
 
void CellBase::FixNodes(void)
 
{
 
  for (list<Node *>::const_iterator i=nodes.begin(); i!=nodes.end(); i++) { 
 
    (*i)->Fix();
 
  }
 
}
 

	
 
// returns true if cell is at border
 
bool CellBase::AtBoundaryP(void) const
 
{
 
  return at_boundary;
 
}
 

	
 

	
 
QString CellBase::printednodelist(void)
 
{
 
  QString info_string = "Nodelist = { ";
 
  for (list<Node *>::const_iterator i =  nodes.begin(); i!=nodes.end(); i++) {
 
    info_string += QString("%1 ").arg((*i)->Index());
 
  }
 
  info_string += " } ";
 
  return info_string;
 
}
 

	
 
/* finis*/
src/cellbase.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  This file is part of the Virtual Leaf.
 
 *
 
 *  The Virtual Leaf is free software: you can redistribute it and/or modify
 
 *  VirtualLeaf 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,
 
 *  VirtualLeaf 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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
// CellBase derives from Vector, where Vector is simply used as a Vertex
 

	
 
#ifndef _CELLBASE_H_
 
#define _CELLBASE_H_
 

	
 
#include <list>
 
#include <vector>
 
#include <iostream>
 
#include <QString>
 
#include <QDebug>
 

	
 
#include "vector.h"
 
#include "parameter.h"
 
#include "wall.h"
 
#include "warning.h"
 
#include "assert.h"
 

	
 
extern Parameter par;
 
using namespace std;
 

	
 
class Mesh;
 
class Node;
 
class CellBase;
 
class NodeSet;
 

	
 
struct ParentInfo {
 

	
 
  Vector polarization;
 
  double PINmembrane;
 
  double PINendosome;
 
};
 

	
 
// We need a little trick here, to make sure the plugin and the main application will see the same static datamembers
 
// otherwise each have their own instantation.
 
// My solution is as follow. I collect all original statics in a class. The main application instantiates it and
 
// My solution is as follows. I collect all original statics in a class. The main application instantiates it and
 
// has a static pointer to it. After loading the plugin I set a static pointer to the same class 
 
class CellsStaticDatamembers {
 

	
 
 public:
 
  CellsStaticDatamembers(void) {
 
    ncells = 0;
 
    nchem = 0;
 
    base_area = 0.;
 
  }
 
  ~CellsStaticDatamembers() {
 
#ifdef QDEBUG
 
    qDebug() << "Oops! Desctructor of CellsStaticDatamembers called" << endl;
 
#endif
 
  }
 
  int ncells;
 
  int nchem;
 
  double base_area;
 
};
 

	
 
class CellBase :  public QObject, public Vector 
 
{
 

	
 
  Q_OBJECT
 

	
 
  friend class Mesh;
 
  friend class CellInfo;
 
  friend class Node;
 
  friend class WallBase;
 
  friend class SimPluginInterface;
 

	
 
 public:
 
  CellBase(QObject *parent=0);
 
  CellBase(double x,double y,double z=0); // constructor
 

	
 
  virtual ~CellBase() {
 
    delete[] chem;
 
    delete[] new_chem;
 
    if (division_axis) delete division_axis;
 
    //cerr << "CellBase " << index << " is dying. " << endl;
 
  }
 

	
 
  CellBase(const CellBase &src); // copy constructor
 
  virtual bool BoundaryPolP(void) const { return false; } 
 

	
 

	
 
  CellBase operator=(const CellBase &src); // assignment operator
 
  CellBase operator=(const Vector &src);
 

	
 
  void SetChemical(int chem, double conc);
 
  inline void SetNewChem(int chem, double conc)
 
  { 
 
    new_chem[chem] = conc;
 
  }
 

	
 
  void SetSource(int chem, double conc)
 
  {
 
    source=true;
 
    source_chem = chem;
 
    source_conc = conc;
 
  }
 

	
 
  // set chem 1 to conc in all membranes of this cell
 
  void SetTransporters(int chem, double conc);
 
  void UnfixNodes(void);
 
  void FixNodes(void);
 
  void UnsetSource(void) {
 
    source = false;
 
  }
 

	
 
  inline bool Source(void) { return source; }
 
  enum boundary_type {None, Noflux, SourceSink, SAM};
 
  static const char * boundary_type_names[4];
 

	
 
  inline const char *BoundaryStr(void) { return boundary_type_names[boundary]; }
 

	
 
  ostream &print(ostream &os) const;
 

	
 
  inline double Chemical(int c) const { // returns the value of chemical c
 
#ifdef _undefined_
 
    qDebug() << endl << "Entering cellbase::chemical(" << c << "), and nchem is: " << NChem() << "." << endl;
 
#endif
 

	
 
    int nchem = NChem();
 

	
 
#ifdef _undefined_
 
    if ((c<0) || (c>=nchem))
 
      MyWarning::warning("CellBase::Chemical says: index c is: %d, but nchem is: %d. Merely return zero", c, nchem);
 
#endif
 

	
 
    return ((c<0) || (c>=nchem)) ? 0 : chem[c];
 
  }
 

	
 

	
 
  //void print_nblist(void) const;
 

	
 
  boundary_type SetBoundary(boundary_type bound)
 
  {
 
    if (bound!=None) {
 
    }
 
    return boundary=bound;
 
  }
 

	
 
  boundary_type ResetBoundary(void) { return boundary=None; }
 

	
 
  boundary_type Boundary(void) const { return boundary; }
 

	
 
  static int &NChem(void) { return static_data_members->nchem; }
 

	
 
  double CalcArea(void) const;
 

	
 
  double RecalcArea(void) { return area = CalcArea(); }
 

	
 
  Vector Centroid(void) const;
 

	
 
  void SetIntegrals(void) const;
 

	
 
  double Length(Vector *long_axis = 0, double *width = 0) const;
 
  double CalcLength(Vector *long_axis = 0, double *width = 0) const;
 

	
 

	
 
  inline int Index(void) const { return index; }
 

	
 

	
 
  void SetTargetArea(double tar_ar) { target_area=tar_ar; }
 

	
 
  inline void SetTargetLength(double tar_l) { target_length=tar_l; }
 

	
 
  inline void SetLambdaLength(double lambda_length) { lambda_celllength = lambda_length; }
 

	
 
  inline double TargetArea(void) { return target_area; }
 

	
 
  inline void SetStiffness(double stiff) { stiffness = stiff; }
 

	
 
  inline double Stiffness(void) { return stiffness; }
 

	
 
  inline double EnlargeTargetArea(double da) { return target_area+=da; }
 

	
 
  inline double Area(void) const { return area; }
 

	
 
  inline void Divide(void) { flag_for_divide = true; }
 

	
 
  inline void DivideOverAxis(const Vector &v)
 
  {
 
    division_axis = new Vector(v);
 
    flag_for_divide = true;
 
  }
 

	
 
  inline double Circumference(void) const {
 
    double sum=0.;
 
    for (list<Wall *>::const_iterator w=walls.begin();
 
	 w!=walls.end();
 
	 w++) {
 
      sum +=  (*w)->Length();
 
    }
 

	
 
    return sum;
 
  }
 

	
 
  QList<WallBase *> getWalls(void) {
 
    QList<WallBase *> wall_list;
 
    for (list<Wall *>::iterator i=walls.begin();
 
	 i!=walls.end();
 
	 i++) {
 
      wall_list << *i;
 
    }
 
    return wall_list;
 
  }
 

	
 
  void Dump(ostream &os) const;
 

	
 
  QString printednodelist(void);
 

	
 
  inline bool DeadP(void) { return dead; }
 
  inline void MarkDead(void) { dead  = true; }
 

	
 
  static double &BaseArea(void)
 
  { 
 
    return static_data_members->base_area;
 
  }
 

	
 
  void CheckForDivision(void);
 

	
 
  // write flux from neighboring cells into "flux"
 
  void Flux(double *flux, double *D); 
 
  inline bool FixedP(void) { return fixed; }
 
  inline bool Fix(void) {  FixNodes(); return (fixed=true); }
 
  inline bool Unfix(void) { UnfixNodes(); return (fixed=false);}
 
  inline void setCellVec(Vector cv) { cellvec = cv; }
 

	
 
  bool AtBoundaryP(void) const;
 

	
 
  static inline int &NCells(void)
 
  {
 
    return static_data_members->ncells;
 
  }
 

	
 
  inline void Mark(void)
 
  {
 
    marked=true;
 
  }
 

	
 
  inline void Unmark(void)
 
  {
 
    marked=false;
 
  }
 

	
 
  inline bool Marked(void) const {
 
    return marked;
 
  }
 

	
 
  //! Returns the sum of chemical "chem" of this CellBase's neighbors
 
  double SumChemicalsOfNeighbors(int chem)
 
  {
 
    double sum=0.;
 
    for (list<Wall *>::const_iterator w=walls.begin();
 
	 w!=walls.end();
 
	 w++) {
 
      sum +=  (*w)->Length() * ( (*w)->c1!=this ? (*w)->c1->Chemical(chem) : (*w)->c2->Chemical(chem) );
 
    }
 
    return sum;
 
  }
 

	
 
  //! Generalization of the previous member function
 
  template<class P, class Op> P ReduceNeighbors(Op f) {
 
    P sum=0;
 
    for (list<Wall *>::const_iterator w=walls.begin();
 
	 w!=walls.end();
 
	 w++) {
 
      sum += (*w)->c1 != this ? f( *((*w)->c1) ) : f ( *((*w)->c2) ); 
 
    }
 
    return sum;
 
  }
 

	
 
  //! The same, but now for the walls
 
  template<class P, class Op> P ReduceWalls(Op f, P sum) {
 
    for (list<Wall *>::const_iterator w=walls.begin();
 
	 w!=walls.end();
 
	 w++) {
 
      sum += f( **w ); 
 
    }
 
    return sum;
 
  }
 

	
 
  //! The same, but now for the walls AND neighbors
 
  template<class P, class Op> P ReduceCellAndWalls(Op f)
 
  {
 
    P sum = 0;
 
    for (list<Wall *>::const_iterator w=walls.begin();
 
	 w!=walls.end();
 
	 w++) {
 
      sum += ((*w)->c1 == this) ? 
 
	f( ((*w)->c1), ((*w)->c2), *w ) :  
 
	f( ((*w)->c2), ((*w)->c1), *w );
 
    }
 
    return sum;
 
  }
 

	
 

	
 
  //! Sum transporters at this CellBase's side of the walls
 
  double SumTransporters(int ch)
 
  {
 
    double sum=0.;
 
    for (list<Wall *>::const_iterator w=walls.begin();
 
	 w!=walls.end();
 
	 w++) {
 
      sum += (*w)->getTransporter(this, ch);
 

	
 
    }
 
    return sum;
 
  }
 

	
 
  inline int NumberOfDivisions(void) { return div_counter; }
 

	
 
  //! Sum transporters at this CellBase's side of the walls
 
  double SumLengthTransporters(int ch)
 
  {
 
    double sum=0.;
 
    for (list<Wall *>::const_iterator w=walls.begin();
 
	 w!=walls.end();
 
	 w++) {
 
      sum += (*w)->getTransporter(this, ch) * (*w)->Length();
 

	
 
    }
 
    return sum;
 
  }
 

	
 

	
 

	
 
  double SumLengthTransportersChemical(int trch, int ch)
 
  {
 
    double sum=0.;
 
    for (list<Wall *>::const_iterator w=walls.begin();
 
	 w!=walls.end();
 
	 w++) {
 
      sum += (*w)->getTransporter(this, trch) * ( (*w)->c1!=this ? (*w)->c1->Chemical(ch) : (*w)->c2->Chemical(ch) );
 

	
 
    }
 
    return sum;
 
  }
 
  inline int CellType(void) const { return cell_type; } 
 
  inline void SetCellType(int ct) { cell_type = ct; }
 

	
 

	
 
  static void SetNChem(int new_nchem)
 
  {
 
    if (NCells()) {
 
      MyWarning::error("CellBase::SetNChem says: not permitted, call SetNChem after deleting all cells.");
 
    } else {
 
      NChem() = new_nchem;
 
    }
 
  }
 

	
 
  inline double TargetLength() const { return target_length; } 
 

	
 
  static inline CellsStaticDatamembers *GetStaticDataMemberPointer(void) { return static_data_members; }
 

	
 
 protected:
 
  // (define a list of Node* iterators)
 
  typedef list < list<Node *>::iterator > ItList;
 

	
 
  int index;
 

	
 
  inline void SetChemToNewchem(void)
 
  {
 
    for (int c=0;c<CellBase::NChem();c++) {
 
      chem[c]=new_chem[c];
 
    }
 
  }
 
  inline void SetNewChemToChem(void)
 
  {
 
    for (int c=0;c<CellBase::NChem();c++) {
 
      new_chem[c]=chem[c];
 
    }
 
  }
 
  inline double NewChem(int c) const { return new_chem[c]; }
 

	
 
 protected:
 
  list<Node *> nodes;
 
  void ConstructNeighborList(void);
 
  long wall_list_index (Wall *elem) const;
 

	
 
  // DATA MEMBERS
 

	
 
  // list of nodes, in clockwise order
 

	
 
  // a (non-ordered) list of neighboring cells (actually I think the
 
  // introduction of ConstructWalls() has made these
 
  // lists ordered (clockwise), but I am not yet 100% sure...).
 
  list<CellBase *> neighbors;
 

	
 
  list<Wall *> walls;
 

	
 
  double *chem;
 
  double *new_chem;
 

	
 
  boundary_type boundary;
 
  mutable double area;
 
  double target_area;
 
  double target_length;
 
  double lambda_celllength;
 

	
 
  double stiffness; // stiffness like in Hogeweg (2000)
 

	
 
  bool fixed;
 
  bool pin_fixed;
 
  bool at_boundary; 
 
  bool dead; 
 
  bool flag_for_divide;
 

	
 
  Vector *division_axis;
 
  int cell_type;
 

	
 
  // for length constraint
 
  mutable double intgrl_xx, intgrl_xy, intgrl_yy, intgrl_x, intgrl_y;
 

	
 
  bool source;
 
  Vector cellvec;
 

	
 
  // STATIC DATAMEMBERS MOVED TO CLASS
 
  static CellsStaticDatamembers *static_data_members;
 
  double source_conc;
 
  int source_chem;
 

	
 
  // PRIVATE MEMBER FUNCTIONS
 
  inline static void ClearNCells(void)
 
  {
 
    NCells()=0;
 
  }
 

	
 
  bool marked;
 
  int div_counter;
 
};
 

	
 
ostream &operator<<(ostream &os, const CellBase &v);
 

	
 
inline Vector PINdir(CellBase *here, CellBase *nb, Wall *w)
 
{
 
  return w->getTransporter( here, 1)  *  w->getInfluxVector(here);
 
}
 

	
 
#endif
 

	
 
/* finis*/
src/cellitem.cpp
Show inline comments
 
/*
 
 *
 
 *  This file is part of the Virtual Leaf.
 
 *
 
 *  The Virtual Leaf is free software: you can redistribute it and/or modify
 
 *  VirtualLeaf 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,
 
 *  VirtualLeaf 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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include <string>
 
#include<QGraphicsScene>
 
#include "cellitem.h"
 

	
 
static const std::string _module_id("$Id$");
 

	
 
CellItem::CellItem( Cell *c, QGraphicsScene *canvas )
 
  : QGraphicsPolygonItem( 0, canvas ), SimItemBase( c, canvas){
 
}
 

	
 
void CellItem::userMove(double dx, double dy)
 
{
 
  QGraphicsPolygonItem::moveBy( dx, dy );
 

	
 
  // also move the cell itself
 
  class_cast<Cell *>(obj)->x += (dx/Cell::Magnification());
 
  class_cast<Cell *>(obj)->y += (dy/Cell::Magnification());
 

	
 
  class_cast<Cell*>(obj)->Move( (dx/Cell::Magnification()), (dy/Cell::Magnification()) );
 
}
 

	
 
QPainterPath CellItem::shape() const { return QGraphicsPolygonItem::shape(); }
 
QRectF CellItem::boundingRect() const { return QGraphicsPolygonItem::boundingRect(); }
 

	
 

	
 
/* finis */
src/cellitem.h
Show inline comments
 
/*
 
 *  VirtualLeaf
 
 *
 
 *  $Id$
 
 *
 
 *  This file is part of the Virtual Leaf.
 
 *
 
 *  The Virtual Leaf is free software: you can redistribute it and/or modify
 
 *  VirtualLeaf 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,
 
 *  VirtualLeaf 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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#ifndef _CELLITEM_H_
 
#define _CELLITEM_H_
 

	
 
#include <QGraphicsScene>
 
#include <QGraphicsPolygonItem>
 
#include <QPainter>
 
#include "simitembase.h"
 
#include "cell.h"
 

	
 

	
 
class CellItem : public QGraphicsPolygonItem, public SimItemBase
 
{
 
 public:
 
  CellItem( Cell *n, QGraphicsScene *canvas );
 
  virtual ~CellItem() {}
 
  Cell &getCell(void) const { return *class_cast<Cell*>(obj); }
 
  virtual void userMove(double dx, double dy);  
 
  QPainterPath shape() const;
 
  QRectF boundingRect() const;
 

	
 
 private:
 
};
 

	
 
#endif
 

	
 
/* finis */
src/forwardeuler.cpp
Show inline comments
 
/*
 
 *
 
 *  This file is part of the Virtual Leaf.
 
 *
 
 *  The Virtual Leaf is free software: you can redistribute it and/or modify
 
 *  VirtualLeaf 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,
 
 *  VirtualLeaf 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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include <cmath>
 
#include <iostream> 
 
#include "forwardeuler.h"
 
#include "warning.h"
 
#include "maxmin.h"
 
#include <string>
 

	
 
using namespace std;
 

	
 
static const string _module_id("$Id$");
 

	
 
// The value Errcon equals (5/Safety) raised to the power (1/PGrow), see use below.
 

	
 
const double ForwardEuler::Safety  = 0.9;
 
const double ForwardEuler::PGrow = -0.2;
 
const double ForwardEuler::Pshrnk = -0.25;
 
const double ForwardEuler::Errcon = 1.89e-4;
 
const double ForwardEuler::Maxstp = 10000000;
 
const double ForwardEuler::Tiny = 1.0e-30;
 

	
 

	
 

	
 
/* User storage for intermediate results. Preset kmax and dxsav in the calling program. If kmax =
 
   0 results are stored at approximate intervals dxsav in the arrays xp[1..kount], yp[1..nvar]
 
   [1..kount], where kount is output by odeint. Defining declarations for these variables, with
 
   memoryallo cations xp[1..kmax] and yp[1..nvar][1..kmax] for the arrays, should be in
 
   the calling program.*/
 

	
 
void ForwardEuler::odeint(double *ystart, int nvar, double x1, double x2, double eps, double h1, double hmin, int *nok, int *nbad)
 
/* Runge-Kutta driver with adaptive stepsize control. Integrate starting values ystart[1..nvar]
 
   from x1 to x2 with accuracy eps, storing intermediate results in global variables. h1 should
 
   be set as a guessed first stepsize, hmin as the minimum allowed stepsize (can be zero). On
 
   output nok and nbad are the number of good and bad (but retried and fixed) steps taken, and
 
   ystart is replaced byv alues at the end of the integration interval. derivs is the user-supplied
 
   routine for calculating the right-hand side derivative, while rkqs is the name of the stepper
 
   routine to be used. */
 
{
 
  static bool warning_issued = false;
 

	
 
  if (!warning_issued) {
 
    cerr << "Using inaccurate method ForwardEuler\n";
 
    warning_issued=true;
 
    //MyWarning::warning("Using inaccurate method ForwardEuler");
 
  }
 
  // N.B. Not for serious use and not fully usage compatible with RungeKutta
 
  // simply for testing API of integrator.
 

	
 
  double *y,*dydx;
 
  y=new double[nvar];
 
  dydx=new double[nvar];
 
  double x=x1;
 

	
 
  for (int i=0;i<nvar;i++) y[i]=ystart[i];
 

	
 
  //if (kmax > 0) xsav=x-dxsav*2.0; //Assures storage of first step.
 

	
 
  dydx=new double[nvar];
 

	
 
  for (int nstp=0;nstp<Maxstp;nstp++) {
 

	
 
    derivs(x,y,dydx);
 

	
 
    if (kmax > 0 && kount < kmax-1) {
 
      xp[kount]=x; //Store intermediate results.
 
      for (int i=0;i<nvar;i++) yp[i][kount]=y[i];
 
      kount++;
 
      //xsav=x;
 
    }
 

	
 
    for (int i=0;i<nvar;i++) {
 
      y[i]=y[i] + h1 * dydx[i];
 
    }
 

	
 
    x = x + h1;
 

	
 
    if ((x-x2)*(x2-x1) >= 0.0) { //Are we done?
 
      goto done;
 
    }
 
  }
 

	
 
 done:
 
  for (int i=0;i<nvar;i++) ystart[i]=y[i];
 
  if (kmax) {
 
    xp[kount]=x; //Save final step.
 
    for (int i=0;i<nvar;i++) yp[i][kount]=y[i];
 

	
 
  }
 

	
 
  delete[] dydx;
 
  delete[] y;
 
  return; //Normal exit.
 
}
 

	
 
/* finis */
src/forwardeuler.h
Show inline comments
 
/*
 
 *  VirtualLeaf
 
 *
 
 *  $Id$
 
 *
 
 *  This file is part of the Virtual Leaf.
 
 *
 
 *  The Virtual Leaf is free software: you can redistribute it and/or modify
 
 *  VirtualLeaf 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,
 
 *  VirtualLeaf 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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#ifndef _FORWARDEULER_H_
 
#define _FORWARDEULER_H_
 

	
 
class ForwardEuler  {
 

	
 
 public:
 
  ForwardEuler(void) {
 
    kmax=kount=0;
 
    dxsav=0.;
 
    xp=0;
 
    yp=0;
 
  }
 

	
 
  virtual ~ForwardEuler() {}
 

	
 
  void odeint(double ystart[], int nvar, double x1, double x2, double eps, double h1,
 
	      double hmin, int *nok, int *nbad);
 

	
 
  // implement this function in a derived class
 
 protected:
 
  virtual void derivs(double x, double *y, double *dxdy) = 0;
 
  int kmax,kount;
 
  double *xp,**yp,dxsav;
 

	
 
 private:
 

	
 
  static const double Safety;
 
  static const double PGrow;
 
  static const double Pshrnk;
 
  static const double Errcon;
 
  static const double Maxstp;
 
  static const double Tiny;
 
};
 
#endif
 

	
 
/* finis */
src/infobar.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  This file is part of the Virtual Leaf.
 
 *
 
 *  The Virtual Leaf is free software: you can redistribute it and/or modify
 
 *  VirtualLeaf 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,
 
 *  VirtualLeaf 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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 

	
 
#ifndef _INFOBAR_H_
 
#define _INFOBAR_H_
 

	
 

	
 
#include <q3mainwindow.h>
 
#include <QLabel>
 
#include <QBoxLayout>
 

	
 
class InfoBar : public Q3DockWindow {
 

	
 
  Q_OBJECT
 
    public:
 

	
 
  InfoBar(void) : Q3DockWindow() { 
 

	
 
    virtleaf = new QLabel();
 
    SetText("undefined");
 

	
 
    setHorizontalStretchable(true);
 
    boxLayout()->addStretch();
 
    boxLayout()->addWidget(virtleaf);//, Qt::AlignHCenter);
 
    boxLayout()->addStretch();
 
  }
 

	
 
  void SetText(QString text) {
 
    virtleaf->setText(QString("<h1>The Virtual Leaf</h1>\n<center><b>Model:</b> <i>%1</i></center>").arg(text));
 
    virtleaf->setText(QString("<h1>VirtualLeaf</h1>\n<center><b>Model:</b> <i>%1</i></center>").arg(text));
 
  }
 

	
 
 private:
 
  QLabel *virtleaf;
 
};
 

	
 
#endif
 

	
 
/* finis */
src/libplugin.pro
Show inline comments
 
#
 
#  $Id$
 
#
 
#  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 <http://www.gnu.org/licenses/>.
 
#
 
#  Copyright 2010 Roeland Merks.
 
#
 

	
 
CONFIG += release
 
CONFIG -= debug
 
CONFIG += staticlib
 

	
 
QMAKE_CXXFLAGS += -fexceptions
 
win32:QMAKE_CXXFLAGS -= O2
 
QMAKE_CXXFLAGS_DEBUG += -g3
 
QMAKE_CXXFLAGS_DEBUG += -DQDEBUG
 
QMAKE_CXXFLAGS_DEBUG -= -finstrument-functions
 

	
 
DEFINES = QTGRAPHICS # VLEAFPLUGIN
 
DESTDIR = ../lib 
 
PARTMPL = VirtualLeafpar.tmpl
 
QT += qt3support
 
TARGET = vleaf
 
TEMPLATE = lib
 

	
 
HEADERS = \
 
 cellbase.h \
 
 matrix.h \
 
 output.h \
 
 parameter.h \
 
 parse.h \
 
 random.h \
 
 simplugin.h \
 
 UniqueMessage.h \
 
 vector.h \
 
 wallbase.h \
 
 warning.h
 

	
 
SOURCES = \
 
 cellbase.cpp \
 
 matrix.cpp \
 
 output.cpp \
 
 parameter.cpp \
 
 parse.cpp \
 
 random.cpp \
 
 simplugin.cpp \
 
 UniqueMessage.cpp \
 
 vector.cpp \
 
 wallbase.cpp \
 
 warning.cpp
 

	
 
unix {
 
 QMAKE_CXXFLAGS += -fPIC -I/usr/include/libxml2
 
 QMAKE_LFLAGS += -fPIC
 
 LIBS += -lxml2 -lz -lm 
 
}
 

	
 
win32 {
 
 LIBXML2DIR = ..\lib\libxml2
 
 LIBICONVDIR = ..\lib\libiconv
 
 LIBZDIR = ..\lib\libz
 
 QMAKE_CXXFLAGS += -DLIBXML_STATIC
 
 LIBXML2DIR = C:
 
 LIBICONVDIR = C:
 
 LIBZDIR = C:
 
# QMAKE_CXXFLAGS += -DLIBXML_STATIC
 
 QMAKE_CXXFLAGS += -I$${LIBXML2DIR}\include -I$${LIBICONVDIR}\include -I$${LIBZDIR}\include
 
}
 

	
 
#
src/mainbase.cpp
Show inline comments
 
/*
 
 *
 
 *  This file is part of the Virtual Leaf.
 
 *
 
 *  The Virtual Leaf is free software: you can redistribute it and/or modify
 
 *  VirtualLeaf 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,
 
 *  VirtualLeaf 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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include <libxml/xpath.h>
 
#include <libxml/xmlreader.h>
 

	
 
#include "mainbase.h"
 
#include "xmlwrite.h"
 

	
 
#include <sstream>
 
#include <string>
 

	
 
#include <QLocale>
 

	
 
static const std::string _module_id("$Id$");
 

	
 
xmlNode *MainBase::XMLViewportTree(QTransform &transform) const {
 
  
 
  QLocale standardlocale(QLocale::C);
 
  
 

	
 
  xmlNode *xmlviewport = xmlNewNode(NULL, BAD_CAST "viewport");
 
  {
 
    xmlNewProp(xmlviewport, BAD_CAST "m11", BAD_CAST standardlocale.toString(transform.m11()).toStdString().c_str() );
 
    xmlNewProp(xmlviewport, BAD_CAST "m12", BAD_CAST standardlocale.toString(transform.m12()).toStdString().c_str() );    
 
    xmlNewProp(xmlviewport, BAD_CAST "m21", BAD_CAST standardlocale.toString(transform.m21()).toStdString().c_str() );    
 
    xmlNewProp(xmlviewport, BAD_CAST "m22", BAD_CAST standardlocale.toString(transform.m22()).toStdString().c_str() );    
 
    xmlNewProp(xmlviewport, BAD_CAST "dx", BAD_CAST standardlocale.toString(transform.dx()).toStdString().c_str() );    
 
    xmlNewProp(xmlviewport, BAD_CAST "dy", BAD_CAST standardlocale.toString(transform.dy()).toStdString().c_str() );    
 
 }
 
  
 
  return xmlviewport;
 
}
 

	
 
xmlNode *MainBase::XMLSettingsTree(void) const {
 

	
 
  xmlNode *xmlsettings = xmlNewNode(NULL, BAD_CAST "settings");
 
  {
 
    xmlNode *xmloption = xmlNewChild(xmlsettings, NULL, BAD_CAST "setting", NULL);
 
    xmlNewProp(xmloption, BAD_CAST "name", BAD_CAST "show_cell_centers");
 
    ostringstream text;
 
    text << bool_name(showcentersp);
 
    xmlNewProp(xmloption, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmloption = xmlNewChild(xmlsettings, NULL, BAD_CAST "setting", NULL);
 
    xmlNewProp(xmloption, BAD_CAST "name", BAD_CAST "show_nodes");
 
    ostringstream text;
 
    text << bool_name(showmeshp);
 
    xmlNewProp(xmloption, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmloption = xmlNewChild(xmlsettings, NULL, BAD_CAST "setting", NULL);
 
    xmlNewProp(xmloption, BAD_CAST "name", BAD_CAST "show_node_numbers");
 
    ostringstream text;
 
    text << bool_name(shownodenumbersp);
 
    xmlNewProp(xmloption, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmloption = xmlNewChild(xmlsettings, NULL, BAD_CAST "setting", NULL);
 
    xmlNewProp(xmloption, BAD_CAST "name", BAD_CAST "show_cell_numbers");
 
    ostringstream text;
 
    text << bool_name(showcellnumbersp);
 
    xmlNewProp(xmloption, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmloption = xmlNewChild(xmlsettings, NULL, BAD_CAST "setting", NULL);
 
    xmlNewProp(xmloption, BAD_CAST "name", BAD_CAST "show_border_cells");
 
    ostringstream text;
 
    text << bool_name(showbordercellp);
 
    xmlNewProp(xmloption, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmloption = xmlNewChild(xmlsettings, NULL, BAD_CAST "setting", NULL);
 
    xmlNewProp(xmloption, BAD_CAST "name", BAD_CAST "show_cell_axes");
 
    ostringstream text;
 
    text << bool_name(showcellsaxesp);
 
    xmlNewProp(xmloption, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmloption = xmlNewChild(xmlsettings, NULL, BAD_CAST "setting", NULL);
 
    xmlNewProp(xmloption, BAD_CAST "name", BAD_CAST "show_cell_strain");
 
    ostringstream text;
 
    text << bool_name(showcellstrainp);
 
    xmlNewProp(xmloption, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmloption = xmlNewChild(xmlsettings, NULL, BAD_CAST "setting", NULL);
 
    xmlNewProp(xmloption, BAD_CAST "name", BAD_CAST "show_fluxes");
 
    ostringstream text;
 
    text << bool_name(showfluxesp);
 
    xmlNewProp(xmloption, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmloption = xmlNewChild(xmlsettings, NULL, BAD_CAST "setting", NULL);
 
    xmlNewProp(xmloption, BAD_CAST "name", BAD_CAST "show_walls");
 
    ostringstream text;
 
    text << bool_name(showwallsp);
 
    xmlNewProp(xmloption, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
 /* {
 
    xmlNode *xmloption = xmlNewChild(xmlsettings, NULL, BAD_CAST "setting", NULL);
 
    xmlNewProp(xmloption, BAD_CAST "name", BAD_CAST "show_apoplasts");
 
    ostringstream text;
 
    text << bool_name(showapoplastsp);
 
    xmlNewProp(xmloption, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  }*/
 
  {
 
    xmlNode *xmloption = xmlNewChild(xmlsettings, NULL, BAD_CAST "setting", NULL);
 
    xmlNewProp(xmloption, BAD_CAST "name", BAD_CAST "save_movie_frames");
 
    ostringstream text;
 
    text << bool_name(movieframesp);
 
    xmlNewProp(xmloption, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmloption = xmlNewChild(xmlsettings, NULL, BAD_CAST "setting", NULL);
 
    xmlNewProp(xmloption, BAD_CAST "name", BAD_CAST "show_only_leaf_boundary");
 
    ostringstream text;
 
    text << bool_name(showboundaryonlyp);
 
    xmlNewProp(xmloption, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmloption = xmlNewChild(xmlsettings, NULL, BAD_CAST "setting", NULL);
 
    xmlNewProp(xmloption, BAD_CAST "name", BAD_CAST "cell_growth");
 
    ostringstream text;
 
    text << bool_name(dynamicscellsp);
 
    xmlNewProp(xmloption, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  {
 
    xmlNode *xmloption = xmlNewChild(xmlsettings, NULL, BAD_CAST "setting", NULL);
 
    xmlNewProp(xmloption, BAD_CAST "name", BAD_CAST "hide_cells");
 
    ostringstream text;
 
    text << bool_name(hidecellsp);
 
    xmlNewProp(xmloption, BAD_CAST "val", BAD_CAST text.str().c_str());
 
  }
 
  return xmlsettings;
 
}
 

	
 
void MainBase::XMLReadViewport(xmlNode *settings) {
 

	
 
  if (settings == 0) {
 
    return;
 
  }
 

	
 
  qreal m11=25,m12=0,m21=0,m22=25,dx=0,dy=0;
 
  QLocale standardlocale(QLocale::C);
 
  xmlNode *cur = settings->xmlChildrenNode;
 

	
 
  while (cur!=NULL) {
 
    
 
    if (!xmlStrcmp(cur->name,(const xmlChar *)"viewport")) {
 
      bool ok;
 
      {
 
	xmlChar *v_str = xmlGetProp(cur, BAD_CAST "m11");
 
	
 
	if (v_str==0) {
 
	  MyWarning::unique_warning("Error reading viewport in mainbase.cpp");
 
	}
 
	if (v_str != NULL) {
 
	  m11=standardlocale.toDouble((char *)v_str, &ok);
 
	  if (!ok) MyWarning::error("Could Not Convert \"%S\" To Double In XMLRead.",(char *)v_str);
 
	  xmlFree(v_str);
 
	}
 
      }
 
      {
 
	xmlChar *v_str = xmlGetProp(cur, BAD_CAST "m12");
 
	
 
	if (v_str==0) {
 
	  MyWarning::unique_warning("Error reading viewport in mainbase.cpp");
 
	}
 
	if (v_str != NULL) {
 
	  m12=standardlocale.toDouble((char *)v_str, &ok);
 
	  if (!ok) MyWarning::error("Could Not Convert \"%S\" To Double In XMLRead.",(char *)v_str);
 
	  xmlFree(v_str);
 
	}
 
      }
 
      { 
 
	xmlChar *v_str = xmlGetProp(cur, BAD_CAST "m21");
 
	
 
	if (v_str==0) {
 
	  MyWarning::unique_warning("Error reading viewport in mainbase.cpp");
 
	}
 
	if (v_str != NULL) {
 
	  m21=standardlocale.toDouble((char *)v_str, &ok);
 
	  if (!ok) MyWarning::error("Could Not Convert \"%S\" To Double In XMLRead.",(char *)v_str);
 
	  xmlFree(v_str);
 
	}
 
      }
 
      {
 
	xmlChar *v_str = xmlGetProp(cur, BAD_CAST "m22");
 
	
 
	if (v_str==0) {
 
	  MyWarning::unique_warning("Error reading viewport in mainbase.cpp");
 
	}
 
	if (v_str != NULL) {
 
	  m22=standardlocale.toDouble((char *)v_str, &ok);
 
	  if (!ok) MyWarning::error("Could Not Convert \"%S\" To Double In XMLRead.",(char *)v_str);
 
	  xmlFree(v_str);
 
	}
 
      }
 
      {
 
	xmlChar *v_str = xmlGetProp(cur, BAD_CAST "dx");
 
	
 
	if (v_str==0) {
 
	  MyWarning::unique_warning("Error reading viewport in mainbase.cpp");
 
	}
 
	if (v_str != NULL) {
 
	  dx=standardlocale.toDouble((char *)v_str, &ok);
 
	  if (!ok) MyWarning::error("Could Not Convert \"%S\" To Double In XMLRead.",(char *)v_str);
 
	  xmlFree(v_str);
 
	}
 
      }
 
      {
 
	xmlChar *v_str = xmlGetProp(cur, BAD_CAST "dy");
 
	
 
	if (v_str==0) {
 
	  MyWarning::unique_warning("Error reading viewport in mainbase.cpp");
 
	}
 
	if (v_str != NULL) {
 
	  dy=standardlocale.toDouble((char *)v_str, &ok);
 
	  if (!ok) MyWarning::error("Could Not Convert \"%S\" To Double In XMLRead.",(char *)v_str);
 
	  xmlFree(v_str);
 
	}
 
      }
 
    }
 
    cur=cur->next;
 
  }
 
  viewport = QTransform(m11,m12,m21,m22,dx,dy);
 
}
 

	
 
void MainBase::XMLReadSettings(xmlNode *settings)
 
{
 

	
 
  // Many files have no settings section, so don't complain about it.
 
  // Defaults will be used instead.
 
  if (settings == 0) {
 
    return;
 
  }
 

	
 
  XMLReadViewport(settings);
 
  xmlNode *cur = settings->xmlChildrenNode;
 

	
 
  while (cur!=NULL) {
 

	
 
    if ((!xmlStrcmp(cur->name, (const xmlChar *)"setting"))){
 

	
 
      xmlChar *name = xmlGetProp(cur, BAD_CAST "name");
 
    
 
      xmlChar *val = xmlGetProp(cur, BAD_CAST "val");
 
      if (!xmlStrcmp(name, (const xmlChar *)"show_cell_centers")) {
 
	showcentersp = strtobool( (const char *)val );
 
      }
 
      if (!xmlStrcmp(name, (const xmlChar *)"show_nodes")) {
 
	showmeshp = strtobool( (const char *)val );
 
      }
 
      if (!xmlStrcmp(name, (const xmlChar *)"show_node_numbers")) {
 
	shownodenumbersp = strtobool( (const char *)val );
 
      }
 
      if (!xmlStrcmp(name, (const xmlChar *)"show_cell_numbers")) {
 
	showcellnumbersp = strtobool( (const char *)val );
 
      }
 
      if (!xmlStrcmp(name, (const xmlChar *)"show_border_cells")) {
 
	showbordercellp = strtobool( (const char *)val );
 
      }
 
      if (!xmlStrcmp(name, (const xmlChar *)"show_cell_axes")) {
 
	showcellsaxesp = strtobool( (const char *)val );
 
      }
 
      if (!xmlStrcmp(name, (const xmlChar *)"show_cell_strain")) {
 
	showcellstrainp = strtobool( (const char *)val );
 
      }
 
      if (!xmlStrcmp(name, (const xmlChar *)"show_fluxes")) {
 
	showfluxesp = strtobool( (const char *)val );
 
      }
 
      if (!xmlStrcmp(name, (const xmlChar *)"show_walls")) {
 
	showwallsp = strtobool( (const char *)val );
 
      }
 
      if (!xmlStrcmp(name, (const xmlChar *)"show_apoplasts")) {
 
     /* if (!xmlStrcmp(name, (const xmlChar *)"show_apoplasts")) {
 
	showapoplastsp = strtobool( (const char *)val );
 
      }
 
      }*/
 
      if (!xmlStrcmp(name, (const xmlChar *)"save_movie_frames")) {
 
	movieframesp = strtobool( (const char *)val );
 
      }
 
      if (!xmlStrcmp(name, (const xmlChar *)"show_only_leaf_boundary")) {
 
	showboundaryonlyp = strtobool( (const char *)val );
 
      }
 
      if (!xmlStrcmp(name, (const xmlChar *)"cell_growth")) {
 
	dynamicscellsp = strtobool( (const char *)val );
 
      }
 
      if (!xmlStrcmp(name,(const xmlChar *)"hide_cells")) {
 
	hidecellsp = strtobool( (const char *)val ); 
 
      }
 
    
 
	
 
  
 
      xmlFree(name);
 
      xmlFree(val);
 
    }
 
    cur=cur->next;
 
  }
 
}
 

	
 
void MainBase::Save(const char *fname, const char *format, int sizex, int sizey)
 
{
 

	
 
  Vector ll,ur;
 
  mesh.BoundingBox(ll, ur);
 

	
 
  if (QString(fname).isEmpty()) {
 
    MyWarning::warning("No output filename given. Saving nothing.\n");
 
    return;
 
  }
 

	
 
  ll*=Cell::Magnification(); ur*=Cell::Magnification();
 

	
 
  // give the leaf some space
 
  Vector border = ((ur-ll)/5.);
 

	
 
  if (!QString(format).contains("pdf", Qt::CaseInsensitive)) {
 

	
 
    QImage *image = new QImage(QSize(sizex, sizey), QImage::Format_RGB32);
 
    image->fill(QColor(Qt::white).rgb());
 
    QPainter *painter=new QPainter(image);
 
    canvas.render(painter);
 
    if (!image->save(QString(fname))) {
 
      MyWarning::warning("Image not saved successfully. Is the disk full or the extension not recognized?");
 
    };
 
    delete painter;
 
    delete image;
 
  } else {
 
    QPrinter pdf(QPrinter::HighResolution);
 
    pdf.setOutputFileName(fname);
 
    pdf.setOutputFormat(QPrinter::PdfFormat);
 
    QPainter painter(&pdf);
 
    canvas.render(&painter, QRectF(), QRectF(-5000,-5000, 10000, 10000));
 

	
 
    cerr << "Rendering to printer\n";
 
  }
 
}
 

	
 
void MainBase::CutSAM()
 
{
 
  mesh.CutAwaySAM();
 
}
 

	
 
/* finis */
src/mainbase.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  This file is part of the Virtual Leaf.
 
 *
 
 *  The Virtual Leaf is free software: you can redistribute it and/or modify
 
 *  VirtualLeaf 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,
 
 *  VirtualLeaf 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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 

	
 
#ifndef _MAINBASE_H_
 
#define _MAINBASE_H_
 

	
 
#include <QGraphicsScene>
 
#include <qpixmap.h>
 
#include <q3picture.h>
 
#include <qpainter.h>
 
#include <qwidget.h>
 
#include <iostream>
 
#include <QGraphicsItem>
 
#include <QPrinter>
 
#include "mesh.h"
 
#include "warning.h"
 

	
 
using namespace std;
 

	
 
/*! Implement these functions in your main application */
 
class MainBase  {
 

	
 
 public:
 
 MainBase(QGraphicsScene &c, Mesh &m) : mesh(m), canvas(c) {
 

	
 
    // Standard options for batch version
 
    showcentersp =  false;
 
    showmeshp =  false;
 
    showbordercellp =  false;
 
    shownodenumbersp =  false;
 
    showcellnumbersp =  false;
 
    showcellsaxesp = false;
 
    showcellstrainp =  false;
 
    movieframesp = true;
 
    showboundaryonlyp =  false;
 
    showwallsp =  false;
 
    showfluxesp = false;
 
    dynamicscellsp = true;
 
    showtooltipsp = false;
 
    hidecellsp = false;
 
  }
 
  virtual ~MainBase() {};
 

	
 
  virtual double TimeStep();
 
  virtual void Init(char *leaffile=0);
 

	
 
  virtual bool ShowCentersP(void) {return showcentersp;}
 
  virtual bool ShowMeshP(void) {return showmeshp; }
 
  virtual bool ShowBorderCellsP(void) {return showbordercellp; }
 
  virtual bool PausedP(void) {return false; }
 
  virtual bool ShowNodeNumbersP(void) {return shownodenumbersp; }
 
  virtual bool ShowCellNumbersP(void) {return showcellnumbersp;}
 
  virtual bool ShowCellAxesP(void) {return showcellsaxesp;}
 
  virtual bool ShowCellStrainP(void) {return showcellstrainp;}
 
  virtual bool MovieFramesP(void) {return movieframesp;}
 
  virtual bool ShowBoundaryOnlyP(void) {return showboundaryonlyp;}
 
  virtual bool ShowToolTipsP(void) {return showtooltipsp;}
 
  virtual bool ShowWallsP(void) {return showwallsp;}
 
  virtual bool ShowApoplastsP(void) { return showapoplastsp;}
 
 // virtual bool ShowApoplastsP(void) { return showapoplastsp;}
 
  virtual bool ShowFluxesP(void) { return showfluxesp; }
 
  virtual bool DynamicCellsP(void) { return dynamicscellsp; }
 
  virtual void FitCanvasToWindow() {};
 
  virtual void FitLeafToCanvas() {};
 
  virtual bool HideCellsP(void) { return hidecellsp; }
 
  virtual void clear(void) {
 
    QList<QGraphicsItem *> list = canvas.items();
 
    QList<QGraphicsItem *>::Iterator it = list.begin();
 
    for (; it != list.end(); ++it) {
 
      if ( *it )
 
	delete *it;
 
    }
 
  };
 
  virtual void XMLReadSettings(xmlNode *settings);
 
  virtual void XMLReadViewport(xmlNode *viewport);
 

	
 
  virtual double getFluxArrowsize(void) { return 10.;}
 

	
 
  void Save(const char *fname, const char *format, int sizex=640, int sizey=480);
 
  void CutSAM(void);
 

	
 
  void Plot(int resize_stride=10);
 

	
 
  virtual void UserMessage(QString message, int timeout = 0) {
 
    cerr << message.toAscii().constData() << endl;
 
  }
 

	
 
  Mesh &mesh;
 
  QTransform viewport;
 

	
 
 protected:
 
  QGraphicsScene &canvas;
 
  virtual xmlNode *XMLSettingsTree(void) const;
 
  virtual xmlNode *XMLViewportTree(QTransform &transform) const;
 
  
 
 protected:
 
  bool showcentersp;
 
  bool showmeshp;
 
  bool showbordercellp;
 
  bool shownodenumbersp;
 
  bool showcellnumbersp;
 
  bool showcellsaxesp;
 
  bool showcellstrainp;
 
  bool movieframesp;
 
  bool showboundaryonlyp;
 
  bool showwallsp;
 
  bool showapoplastsp;
 
//  bool showapoplastsp;
 
  bool showfluxesp;
 
  bool dynamicscellsp;
 
  bool showtooltipsp;
 
  bool hidecellsp;
 
};
 

	
 
//#include <qapplication.h>
 
#define TIMESTEP double MainBase::TimeStep(void)
 
#define INIT void MainBase::Init(char *leaffile)
 

	
 
#endif
 

	
 
/* finis */
src/matrix.cpp
Show inline comments
 
/*
 
 *
 
 *  This file is part of the Virtual Leaf.
 
 *
 
 *  The Virtual Leaf is free software: you can redistribute it and/or modify
 
 *  VirtualLeaf 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,
 
 *  VirtualLeaf 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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include <string>
 
#include <ostream>
 
#include <cmath>
 
#include "vector.h"
 
#include "matrix.h"
 
#include "tiny.h"
 

	
 
static const std::string _module_id("$Id$");
 

	
 
Matrix::Matrix(const Vector &c1, const Vector &c2, const Vector &c3) {
 

	
 
  Alloc();
 

	
 
  mat[0][0]=c1.x; mat[0][1]=c2.x; mat[0][2]=c3.x;
 
  mat[1][0]=c1.y; mat[1][1]=c2.y; mat[1][2]=c3.y;
 
  mat[2][0]=c1.z; mat[2][1]=c2.z; mat[2][2]=c3.z;
 
}
 

	
 
void Matrix::Alloc(void)
 
{
 
  // constructor
 
  mat = new double*[3];
 
  mat[0] = new double[9];
 
  for (int i=1;i<3;i++)
 
    mat[i]=mat[i-1]+3;
 
}
 

	
 
Matrix::~Matrix()
 
{
 
  // destructor
 
  delete[] mat[0];
 
  delete[] mat;
 
}
 

	
 
Matrix::Matrix(void)
 
{
 
  // constructor
 
  Alloc();
 

	
 
  // clear matrix
 
  for (int i=0;i<9;i++) {
 
    mat[0][i]=0.;
 
  }
 
}
 

	
 
Matrix::Matrix(const Matrix &source)
 
{
 
  // copy constructor
 
  Alloc();
 

	
 
  for (int i=0;i<9;i++) {
 
    mat[0][i]=source.mat[0][i];
 
  }
 
}
 

	
 

	
 
void Matrix::operator=(const Matrix &source)
 
{
 
  // assignment
 

	
 
  // don't assign to self
 
  if (this==&source) return;
 

	
 
  // copy 
 
  for (int i=0;i<9;i++)
 
    mat[0][i]=source.mat[0][i];
 
}
 

	
 

	
 
void Matrix::print(ostream *os)
 
{
 
  *os << "{ { " << mat[0][0] << "," << mat[0][1] << "," << mat[0][2] 
 
      << "},{" << mat[1][0] << "," << mat[1][1] << "," << mat[1][2] 
 
      << "},{" << mat[2][0] << "," << mat[2][1] << "," << mat[2][2] << "} }";
 
}
 

	
 
ostream &operator<<(ostream &os, Matrix &v) {
 
  v.print(&os);
 
  return os;
 
}
 

	
 

	
 
Vector Matrix::operator*(const Vector &v) const
 
{
 
  // matrix * vector
 
  Vector result;
 

	
 
  result.x = mat[0][0]*v.x+mat[0][1]*v.y+mat[0][2]*v.z;
 
  result.y = mat[1][0]*v.x+mat[1][1]*v.y+mat[1][2]*v.z;
 
  result.z = mat[2][0]*v.x+mat[2][1]*v.y+mat[2][2]*v.z;
 

	
 
  return result;
 
}
 

	
 

	
 
bool Matrix::operator==(Matrix &m) const
 
{
 
  for (int i=0;i<9;i++) {
 
    if ((mat[0][i]-m.mat[0][i])>TINY)
 
      return false;
 
  }
 
  return true;
 
}
 

	
 
double Matrix::Det(void) const
 
{
 
  return 
 
    - mat[0][2]*mat[0][4]*mat[0][6]
 
    + mat[0][1]*mat[0][5]*mat[0][6] 
 
    + mat[0][2]*mat[0][3]*mat[0][7]
 
    - mat[0][0]*mat[0][5]*mat[0][7]
 
    - mat[0][1]*mat[0][3]*mat[0][8]
 
    + mat[0][0]*mat[0][4]*mat[0][8];
 
}
 

	
 
Matrix Matrix::Inverse(void) const
 
{
 

	
 
  // return the Inverse of this matrix
 
  double rd=1./Det(); // Reciproce Det;
 
  Matrix inverse;
 
  inverse.mat[0][0]=rd*(-mat[0][5]*mat[0][7]+mat[0][4]*mat[0][8]);
 
  inverse.mat[0][1]=rd*( mat[0][2]*mat[0][7]-mat[0][1]*mat[0][8]);
 
  inverse.mat[0][2]=rd*(-mat[0][2]*mat[0][4]+mat[0][1]*mat[0][5]);
 
  inverse.mat[0][3]=rd*( mat[0][5]*mat[0][6]-mat[0][3]*mat[0][8]);
 
  inverse.mat[0][4]=rd*(-mat[0][2]*mat[0][6]+mat[0][0]*mat[0][8]);
 
  inverse.mat[0][5]=rd*( mat[0][2]*mat[0][3]-mat[0][0]*mat[0][5]);
 
  inverse.mat[0][6]=rd*(-mat[0][4]*mat[0][6]+mat[0][3]*mat[0][7]);
 
  inverse.mat[0][7]=rd*( mat[0][1]*mat[0][6]-mat[0][0]*mat[0][7]);
 
  inverse.mat[0][8]=rd*(-mat[0][1]*mat[0][3]+mat[0][0]*mat[0][4]);
 

	
 
  return inverse;
 
}
 

	
 
void Matrix::Rot2D(double theta)
 
{ 
 
  // make this matrix a rotation matrix over theta
 
  // see http://mathworld.wolfram.com/RotationMatrix.html
 

	
 
  mat[0][0] = cos(theta); mat[0][1]=sin(theta);
 
  mat[1][0] = -sin(theta); mat[1][1]=cos(theta);
 
  mat[0][2] = mat[1][2] = mat[2][0] = mat[2][1] = mat[2][2] = 0.;
 
}
 

	
 
/* finis */
src/matrix.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  This file is part of the Virtual Leaf.
 
 *
 
 *  The Virtual Leaf is free software: you can redistribute it and/or modify
 
 *  VirtualLeaf 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,
 
 *  VirtualLeaf 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 <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 

	
 
#ifndef _MATRIX_H_
 
#define _MATRIX_H_
 

	
 
// three by three matrix (mostly for changes of basis of the vector object)
 
class Vector;
 

	
 
class Matrix {
 

	
 
 public:
 
  Matrix(const Vector &v1,const Vector &v2, const Vector &v3); // constructor
 
  Matrix(void);
 
  ~Matrix(); // destructor
 

	
 
  void print(ostream *os);
 
  Matrix(const Matrix &source); // copy constructor
 
  void operator=(const Matrix &source); // assignment operator
 

	
 
  Vector operator*(const Vector &v) const; // matrix * vector
 
  bool operator==(Matrix &v) const; // comparison
 
  double Det(void) const; // gives the "determinant" (| m |) of m
 
  Matrix Inverse(void) const; // gives the inverse of m
 
  void Rot2D(double theta); // make a matrix doing a 2D rotation over theta
 
  // data members 
 
  double **mat;
 

	
 
 private:
 

	
 
  void Alloc(void);
 
};
 

	
 
ostream &operator<<(ostream &os, Matrix &v);
 

	
 
#endif
 

	
 
/* finis */

Changeset was too big and was cut off... Show full diff anyway

0 comments (0 inline, 0 general)