Changeset - a58b80c85b6f
[Not reviewed]
default
0 46 0
Michael Guravage - 15 years ago 2010-06-17 12:25:40
michael.guravage@cwi.nl
Cleanup: e.g. removed commented out and otherwise disabled code.
--
user: Michael Guravage <michael.guravage@cwi.nl>
branch 'default'

changed src/OptionFileDialog.cpp
changed src/OptionFileDialog.h
changed src/UniqueMessage.cpp
changed src/VirtualLeaf.cpp
changed src/apoplastitem.cpp
changed src/apoplastitem.h
changed src/build_models/auxingrowthplugin.cpp
changed src/build_models/meinhardtplugin.cpp
changed src/build_models/testplugin.h
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/data_plot.cpp
changed src/data_plot.h
changed src/flux_function.h
changed src/forwardeuler.cpp
changed src/infobar.h
changed src/mainbase.cpp
changed src/mainbase.h
changed src/matrix.cpp
changed src/mesh.h
changed src/modelcatalogue.cpp
changed src/node.cpp
changed src/node.h
changed src/nodeitem.cpp
changed src/nodeset.h
changed src/output.cpp
changed src/output.h
changed src/parse.cpp
changed src/parse.h
changed src/random.cpp
changed src/random.h
changed src/sqr.h
changed src/vector.h
changed src/vleafmodel.h
changed src/wall.cpp
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
46 files changed with 332 insertions and 1831 deletions:
0 comments (0 inline, 0 general)
src/OptionFileDialog.cpp
Show inline comments
 
@@ -15,39 +15,35 @@
 
 *  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);
 
	
 
	//timecheck = new QCheckBox("time",this);
 
	//timecheck -> setCheckState(Qt::Checked);
 
	
 
	addToolButton(geometrycheck);
 
	//addToolButton(timecheck);
 
	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";
 
					
 
	};
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
 
 *  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.
 
 *
 
 */
 

	
 
#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;
 
	//QCheckBox *timecheck;
 
	
 
};
 

	
 
};
 
#endif
src/UniqueMessage.cpp
Show inline comments
 
@@ -21,59 +21,55 @@
 

	
 
#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"));
 
	//addButton(show_again, QMessageBox::ActionRole);
 
	//addButton(QMessageBox::Ok);
 
	okButton = new QPushButton(tr("Ok"));
 
		
 
	if (issued_messages.contains(boxtext) ) {
 
		
 
		cerr << "Saw message before\n";
 
		display = false;
 
	} else {
 
		//cerr << "First time message\n";
 
		//issued_messages << text;
 
		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)  {
 
	
src/VirtualLeaf.cpp
Show inline comments
 
@@ -36,60 +36,53 @@
 
#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"
 

	
 
/* #define _xstr_(s) _str_(s)
 
   #define _str_(s) #s
 
   #include _xstr_(REACTIONS_HEADER)
 
*/
 

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

	
 
extern Parameter par;
 

	
 
MainBase *main_window = 0;
 
//double auxin_account = 0.;
 

	
 

	
 
#ifdef XFIGGRAPHICS
 
#define TIMESTEP double Graphics::TimeStep(void)
 
#endif
 

	
 
class PrintNode {
 
public:
 
  void operator() (const Node &n) const 
 
  {
 
    cerr << n.Index() << ": " << n <<  endl;
 
  }
 
};
 

	
 

	
 
class EdgeSource {
 
	
 
public:
 
  void operator() (Cell &c) {
 
		
 
    if (c.AtBoundaryP()) {
 
      cerr << "Cell " << c.Index() << " is a source cell.\n";
 
      c.SetSource(0,par.source);
 
    } else {
 
      cerr << "Cell " << c.Index() << " is _not_ a source cell.\n";
 
@@ -171,58 +164,48 @@ void MainBase::Plot(int resize_stride) {
 
  if (ShowWallsP())
 
    mesh.LoopWalls( bind2nd( mem_fun_ref( &Wall::Draw ), &canvas ) );
 
	
 
  if (ShowApoplastsP()) 
 
    mesh.LoopWalls( bind2nd( mem_fun_ref( &Wall::DrawApoplast ), &canvas ) );
 
 
 
  if (ShowMeshP()) 
 
    mesh.DrawNodes(&canvas);
 
	
 
  if (ShowBoundaryOnlyP()) 
 
    mesh.DrawBoundary(&canvas);
 

	
 
  if ( ( batch || MovieFramesP() )) {
 
		
 
    static int frame = 0;
 
    // frame numbers are sequential for the most frequently written file type.
 
    // for the less frequently written file type they match the other type
 
    if (!(count%par.storage_stride) )  {
 
		
 
      stringstream fname;
 
      fname << par.datadir << "/leaf.";
 
      fname.fill('0');
 
      fname.width(6);
 
	
 
      /* 
 
	 fname << frame << ".pdf";
 
	 if (par.storage_stride <= par.xml_storage_stride) {
 
	 frame++;
 
	 }
 
			
 
	 // Write high-res JPG snapshot every plot step
 
	 Save(fname.str().c_str(), "PDF");
 
      */
 
			
 
      fname << frame << ".jpg";
 
      if (par.storage_stride <= par.xml_storage_stride) {
 
	frame++;
 
      }
 
			
 
      // Write high-res JPG snapshot every plot step
 
      Save(fname.str().c_str(), "JPEG",1024,768);
 
    }
 
	
 
    if (!(count%par.xml_storage_stride)) {
 
      stringstream fname;
 
      fname << par.datadir << "/leaf.";
 
      fname.fill('0');
 
      fname.width(6);
 
      fname << frame << ".xml";
 
	
 
      if (par.xml_storage_stride < par.storage_stride) {
 
	frame++;
 
      }
 
      // Write XML file every ten plot steps
 
      mesh.XMLSave(fname.str().c_str(), XMLSettingsTree());
 
    }
 
  }
 
}
 
@@ -256,108 +239,74 @@ TIMESTEP {
 
  }
 
			 
 
  ncells=mesh.NCells();
 
		
 
				
 
  double dh;
 
  		
 
  if(DynamicCellsP()) {
 
    dh = mesh.DisplaceNodes();
 
			
 
    // Only allow for node insertion, cell division and cell growth
 
    // if the system has equillibrized
 
    // i.e. cell wall tension equillibrization is much faster
 
    // than biological processes, including division, cell wall yielding
 
    // and cell expansion
 
    mesh.InsertNodes(); // (this amounts to cell wall yielding)
 
			
 
    if ( (-dh) < par.energy_threshold) {
 
				
 
      mesh.IncreaseCellCapacityIfNecessary();
 
      mesh.DoCellHouseKeeping();
 
      //mesh.LoopCurrentCells(mem_fun(&plugin->CellHouseKeeping)); // this includes cell division
 
				
 
      // Reaction diffusion	
 
      /*CelltoCellTransport *transport_f = &TestPlugin::CelltoCellTransport;
 
	CellReaction *cellreaction_f = new plugin->CellDynamics();
 
	WallReaction *wall_f = new WallDynamics();*/
 
				
 
      mesh.ReactDiffuse(par.rd_dt);
 
				
 
      t++;
 
				
 
      Plot(par.resize_stride);
 
		
 
      /*QVector< QPair<double, int> > angles=mesh.VertexAnglesValues();
 
	QString afname=QString("Angles/anglesvalues%1.dat").arg(t,6,10,QChar('0'));
 
	ofstream af(afname.toStdString().c_str());
 
      */
 
		
 
      /*for (QVector< QPair<qreal, int> >::const_iterator v=angles.begin();
 
	v!=angles.end();
 
	v++) {
 
	af << v->first << " " << v->second << endl;
 
	}
 
      */
 
    }
 
		
 
  } else {
 
			
 
    /*  TransportFunction *transport_f = new CelltoCellTransport();
 
	CellReaction *cellreaction_f = new CellDynamics();
 
	WallReaction *wall_f = new WallDynamics();
 
			
 
	mesh.ReactDiffuse_New(transport_f, cellreaction_f, wall_f, par.rd_dt);*/
 
    mesh.ReactDiffuse(par.rd_dt);
 
		
 
    Plot(par.resize_stride);
 
			
 
  }
 
		
 
  i++;
 
  return mesh.getTime();
 
		
 
}
 
		
 
		
 
				
 
/* Called if a cell is clicked */
 
void Cell::OnClick(QMouseEvent *e) {
 

	
 
  e = NULL; // use assignment merely to obviate compilation warning
 

	
 
  /* #ifdef HAVE_QWT
 
  // Launch DataPlot window
 
  QStringList curvenames;
 
  for (int i=0;i<NChem();i++) {
 
  curvenames += QString("Chem #%1").arg(i);
 
  }
 
  PlotDialog *plot = new PlotDialog((Main *)main_window, QString("Monitor for Cell %1").arg(Index()), curvenames);
 
  QObject::connect(this, SIGNAL(ChemMonValue(double, double *)),
 
  plot, SLOT(AddValue(double,double *)));
 
  #endif
 
  */
 
  //getMesh().plugin->OnClick(*this);
 
}
 
				
 

	
 
/* Custom message handler - Default appends a newline character to the end of each line. */ 
 
void vlMessageOutput(QtMsgType type, const char *msg)
 
{
 
  switch (type) {
 
  case QtDebugMsg:
 
    //fprintf(stderr, "Debug: %s\n", msg);
 
    cerr << msg << flush;
 
    break;
 
  case QtWarningMsg:
 
    //fprintf(stderr, "Warning: %s\n", msg);
 
    cerr << "Warning: " << msg << flush;
 
    break;
 
  case QtCriticalMsg:
 
    fprintf(stderr, "Critical: %s\n", msg);
 
    cerr << "Critical: " << msg << flush;
 
    break;
 
  case QtFatalMsg:
 
    //fprintf(stderr, "Fatal: %s\n", msg);
 
    cerr << "Fatal: " << msg << flush;
 
    abort();
 
  }
 
@@ -457,59 +406,48 @@ int main(int argc,char **argv) {
 

	
 
	  
 
    if (useGUI) {
 
      main_window=new Main(canvas, mesh);
 
      if ( QApplication::desktop()->width() > ((Main *)main_window)->width() + 10
 
	   && QApplication::desktop()->height() > ((Main *)main_window)->height() +30 ) {
 

	
 
	((Main *)main_window)->show();
 
	((Main *)main_window)->resize( ((Main *)main_window)->sizeHint());
 
      } else {
 
        ((Main *)main_window)->showMaximized();
 
      }
 
    } else {
 
      main_window=new MainBase(canvas, mesh);
 

	
 
    }
 

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

	
 
    // Load plugins
 
    /*QVector<SimPluginInterface *> plugins = LoadPlugins();
 
      InstallPlugin(plugins[0], main_window);
 
	  
 
      cerr << "List of models:" << endl;
 
      foreach (SimPluginInterface *p, plugins) {
 
      cerr << p->ModelID().toStdString() << endl;
 
      }
 
    */
 

	
 
	 	  
 
    // 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
src/apoplastitem.cpp
Show inline comments
 
@@ -22,54 +22,54 @@
 
 */
 

	
 

	
 
#include <string>
 
#include <QGraphicsScene>
 
#include "canvas.h"
 
#include "parameter.h"
 
#include "node.h"
 
#include "apoplastitem.h"
 

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

	
 
ApoplastItem::ApoplastItem( Wall *w, QGraphicsScene *canvas )
 
: QGraphicsLineItem( 0, canvas ), SimItemBase( w, canvas){
 
		
 
	setColor();
 
	
 
	// line with "PIN1"is a bit inside the cell wall
 
	Vector edgevec = (*(w->N2())) - (*(w->N1()));
 
	Vector perp = edgevec.Normalised().Perp2D();
 
	
 
	Vector offs = Cell::Offset();
 
	double factor = Cell::Factor();
 
	
 
	Vector from = ( offs + *(w->N1()) ) * factor;// + (wn==1?-1:1) * par.outlinewidth;// * 0.2 * factor * perp;
 
	Vector to = ( offs + *(w->N2()) ) *factor;// + (wn==1?-1:1) * par.outlinewidth;// * 0.2 * factor * perp;
 
	Vector from = ( offs + *(w->N1()) ) * factor;
 
	Vector to = ( offs + *(w->N2()) ) *factor;
 
	
 
	
 
	setLine(( from.x ),
 
			( from.y ),
 
			( to.x ),
 
			( to.y ) );
 
	setZValue(12);
 
}
 

	
 

	
 
void ApoplastItem::setColor(void) {
 
	
 
	QColor diffcolor;
 
	static const QColor purple("Purple");
 
	static const QColor blue("blue");
 
	
 
	Wall *w=&getWall();
 
	double val = w->getApoplast(2);
 

	
 
	diffcolor.setRgb( 0,0,(int)( ( val / (1 + val) )*255.));
 
	setPen (QPen(diffcolor, 20) );
 

	
 
}
 

	
 
void ApoplastItem::OnClick(QMouseEvent *e) {
 
  e = NULL; // merely to obviate compile time warning
 
  e = NULL; // merely to obviate compilation warnings
 
}
 

	
src/apoplastitem.h
Show inline comments
 
@@ -19,32 +19,30 @@
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#ifndef _APOPLASTITEM_H_
 
#define _APOPLASTITEM_H_
 
#include <QGraphicsScene>
 
#include <QGraphicsLineItem>
 
#include <QPainter>
 
#include <qpainter.h>
 
#include <QMouseEvent>
 
#include "simitembase.h"
 
#include "wall.h"
 

	
 
//! Shows transporter concentrations at one side of the wall
 

	
 
class ApoplastItem : public QGraphicsLineItem, public SimItemBase
 
{
 
public:
 
	ApoplastItem( Wall *n, QGraphicsScene *canvas );
 
	virtual ~ApoplastItem() {}
 
	Wall &getWall(void) const { return *class_cast<Wall*>(obj); }
 
	void OnClick(QMouseEvent *e);  
 
	//virtual void userMove(double dx, double dy);  
 
	//virtual void paint( QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0);
 
	void setColor(void);
 
private:
 
	int wn;
 
};
 

	
 
#endif
src/build_models/auxingrowthplugin.cpp
Show inline comments
 
@@ -37,262 +37,238 @@ bool batch = false;
 

	
 

	
 
// To be executed after cell division
 
void AuxinGrowthPlugin::OnDivide(ParentInfo *parent_info, CellBase *daughter1, CellBase *daughter2) {
 
  parent_info = NULL; // merely to obviate compile time error
 

	
 
	// Auxin distributes between parent and daughter according to area
 
	double area1 = daughter1->Area(), area2 = daughter2->Area();
 
	double tot_area = area1 + area2;
 
	
 
	daughter1->SetChemical(0,daughter1->Chemical(0)*(area1/tot_area));
 
	daughter2->SetChemical(0,daughter2->Chemical(0)*(area2/tot_area));
 
	
 
	// After divisions, parent and daughter cells get a standard stock of PINs.
 
	daughter1->SetChemical(1, par->initval[1]);
 
	daughter2->SetChemical(1, par->initval[1]);
 
	
 
	
 
	// Reset transporter values of parent and daughter
 
	QList<WallBase *> walls;
 
	foreach(WallBase *w, walls) { 
 
		w->setTransporter(daughter1, 1, 0.);
 
	}
 
	
 
	//daughter1.LoopWalls(Wall::setTransporter(&daughter1, 1, 0.));
 
	
 
	
 
	/* for (list<Wall *>::const_iterator w=daughter2.walls.begin();
 
		 w!=daughter2.walls.end();
 
		 w++) {
 
		// reset transporter value
 
		(*w)->setTransporter(&daughter2, 1, 0.);
 
	}
 
	*/
 
}
 

	
 
void AuxinGrowthPlugin::SetCellColor(CellBase *c, QColor *color) { 
 

	
 
	// Red: PIN1
 
	// Green: Auxin
 
	if (c->CellType()==1) color->setNamedColor("Blue"); 
 
	else color->setRgb(c->Chemical(1)/(1+c->Chemical(1)) * 255.,(c->Chemical(0)/(1+c->Chemical(0)) * 255.),/* (chem[2]/(1+chem[2]) *255.) */ 0);
 
	
 
}
 

	
 

	
 

	
 
void AuxinGrowthPlugin::CellHouseKeeping(CellBase *c) {
 

	
 
	if (c->Boundary()==CellBase::None) {
 
		if (c->Area() > par->rel_cell_div_threshold * c->BaseArea() ) {
 
			c->SetChemical(0,0);
 
			c->Divide();
 
        }		
 
		if (c->Chemical(0)>0.6) {
 
			c->SetCellType(1);
 
		} 
 
		// expand according to auxin concentration
 
   		c->EnlargeTargetArea(par->auxin_dependent_growth?(c->Chemical(0)/(1.+c->Chemical(0)))*par->cell_expansion_rate:par->cell_expansion_rate);
 
	}  
 
	
 

	
 
}
 

	
 
void AuxinGrowthPlugin::CelltoCellTransport(Wall *w, double *dchem_c1, double *dchem_c2) {
 

	
 
	// leaf edge is const source of auxin
 
    // (Neumann boundary condition: we specify the influx)
 
    if (w->C2()->BoundaryPolP()) {
 
		if (w->AuxinSource()) {
 
			double aux_flux = par->leaf_tip_source * w->Length();
 
			dchem_c1[0]+= aux_flux;
 
			// dchem_c2 is undefined..!
 
			return;
 
		} else {
 
			return;
 
		}
 
	}
 
	
 
	
 
	if (w->C1()->BoundaryPolP()) {
 
		
 
		if (w->AuxinSource()) {
 
			double aux_flux = par->leaf_tip_source * w->Length();
 
			dchem_c2[0] += aux_flux;
 
			// dchem_c1 is undefined...!
 
			return;
 
		} else {
 
			
 
			if (w->AuxinSink()) {
 
				
 
				// efflux into Shoot Apical meristem
 
				// we assume all PINs are directed towards shoot apical meristem
 
				dchem_c2[0] -= par->sam_efflux * w->C2()->Chemical(0) / (par->ka + w->C2()->Chemical(0));
 
				
 
				return;
 
			} else 
 
				return;
 
		}
 
    }
 
	
 
    
 
	// Passive fluxes (Fick's law)
 
    // only auxin flux now
 
    // flux depends on edge length and concentration difference
 
    int c=0;
 
    double phi = w->Length() * ( par->D[c] ) * ( w->C2()->Chemical(c) - w->C1()->Chemical(c) );
 
    dchem_c1[c] += phi; 
 
    dchem_c2[c] -= phi;
 
	
 
    // Active fluxes (PIN1 mediated transport)
 
	
 
    // (Transporters measured in moles, here)
 
    // efflux from cell 1 to cell 2
 
    double trans12 = ( par->transport * w->Transporters1(1) * w->C1()->Chemical(0) / (par->ka + w->C1()->Chemical(0)) );
 
	
 
    // efflux from cell 2 to cell 1
 
    double trans21 = ( par->transport * w->Transporters2(1) * w->C2()->Chemical(0) / (par->ka + w->C2()->Chemical(0)) );
 
    
 
    dchem_c1[0] += trans21 - trans12;
 
    dchem_c2[0] += trans12 - trans21;
 
	
 
}
 

	
 
void AuxinGrowthPlugin::WallDynamics(Wall *w, double *dw1, double *dw2) {
 

	
 
	
 
	
 
    // Cells polarize available PIN1 to Shoot Apical Meristem
 
    if (w->C2()->BoundaryPolP()) {
 
		if (w->AuxinSink()) {
 
			
 
			dw1[0] = 0.; dw2[0] = 0.;
 
			//dw1[2] = 0.; dw2[2] = 0.;
 
            
 
			// assume high auxin concentration in SAM, to convince PIN1 to polarize to it
 
			// exocytosis regulated0
 
			double nb_auxin = par->sam_auxin;
 
			double receptor_level = nb_auxin * par->r / (par->kr + nb_auxin);
 
			
 
			dw1[1] = par->k1 * w->C1()->Chemical(1) * receptor_level /( par->km + w->C1()->Chemical(1) ) - par->k2 * w->Transporters1(1);
 
			
 
			dw2[1] = 0.;
 
			return;
 
			
 
		} else {
 
			dw1[0]=dw2[0]=dw1[1]=dw2[1];//=dw1[2]=dw2[2];
 
			dw1[0]=dw2[0]=dw1[1]=dw2[1];
 
			return;
 
		}
 
    }
 
    
 
    if (w->C1()->BoundaryPolP()) {
 
		if (w->AuxinSink())  {
 
			
 
			dw1[0] = 0.; dw2[0] = 0.;
 
			//dw1[2] = 0.; dw2[2] = 0.;
 
			
 
			// assume high auxin concentration in SAM, to convince PIN1 to polarize to it
 
			// exocytosis regulated
 
			double nb_auxin = par->sam_auxin;
 
			double receptor_level = nb_auxin * par->r / (par->kr + nb_auxin);
 
			dw2[1] = par->k1 * w->C2()->Chemical(1) * receptor_level /( par->km + w->C2()->Chemical(1) ) - par->k2 * w->Transporters2(1);
 
			
 
			dw1[1] = 0.;
 
			return;
 
			
 
		}  else {
 
			dw1[0]=dw2[0]=dw1[1]=dw2[1];//=dw1[2]=dw2[2];
 
			dw1[0]=dw2[0]=dw1[1]=dw2[1];
 
			return;
 
		}
 
    }
 
    
 
    
 
    
 
    // PIN1 localization at wall 1
 
    // Note: chemical 0 is Auxin (intracellular storage only)
 
    // Chemical 1 is PIN1 (walls and intracellular storage)
 
    //! \f$ \frac{d Pij/dt}{dt} = k_1 A_j \frac{P_i}{L_ij} - k_2 P_{ij} \f$
 
    // Note that Pij is measured in term of concentration (mol/L)
 
    // Pi in terms of quantity (mol)
 
	
 
    double dPijdt1=0., dPijdt2=0.;
 
    
 
    // normal cell
 
    double  auxin2 = w->C2()->Chemical(0);
 
    double receptor_level1 = auxin2 * par->r / (par->kr + auxin2);
 
    
 
    dPijdt1 = 
 
	// exocytosis regulated
 
    par->k1 * w->C1()->Chemical(1) * receptor_level1 / ( par->km + w->C1()->Chemical(1) ) - par->k2 * w->Transporters1(1);
 
	
 
    double  auxin1 = w->C1()->Chemical(0);
 
    double receptor_level2 = auxin1 * par->r / (par->kr + auxin1);
 
    
 
    // normal cell
 
    dPijdt2 = 
 
	
 
	// exocytosis regulated
 
	par->k1 * w->C2()->Chemical(1) * receptor_level2 / ( par->km + w->C2()->Chemical(1) ) - par->k2 * w->Transporters2(1);
 
    
 
    /* PIN1 of neighboring vascular cell inhibits PIN1 endocytosis */
 
    
 
    dw1[0] = 0.; dw2[0] = 0.;
 
    //dw1[2] = 0.; dw2[2] = 0.;
 
    
 
    dw1[1] = dPijdt1;
 
    dw2[1] = dPijdt2;
 
}
 

	
 
double AuxinGrowthPlugin::complex_PijAj(CellBase *here, CellBase *nb, Wall *w) { 
 
	
 
	// gives the amount of complex "auxinreceptor-Pin1"  at the wall (at QSS) 
 
	//return here.Chemical(1) * nb.Chemical(0) / ( par->km + here.Chemical(1));
 
	
 
	double nb_aux = (nb->BoundaryPolP() && w->AuxinSink()) ? par->sam_auxin : nb->Chemical(0);
 
	double receptor_level = nb_aux * par->r / (par->kr + nb_aux);
 
	
 
	return here->Chemical(1) * receptor_level / ( par->km + here->Chemical(1));
 
	
 
}
 

	
 
void AuxinGrowthPlugin::CellDynamics(CellBase *c, double *dchem) {
 
	// Note: Pi and Pij measured in numbers of molecules, not concentrations		
 
		double dPidt = 0.;
 
		
 
		double sum_Pij = c->SumTransporters( 1 );
 
		
 
		// exocytosis regulated:
 
	
 
	dPidt = -par->k1 * c->ReduceCellAndWalls<double>( far_3_arg_mem_fun( *this, &AuxinGrowthPlugin::complex_PijAj ) ) + par->k2 * sum_Pij;
 
	/*for ( list<Wall *>::const_iterator w = c->walls.begin();
 
		 w!=walls.end();
 
		 w++) {
 
		if ((*w)->C1() == c)
 
			dPidt +=  complex_PijAj( (*w)->C1(), (*w)->C2(), *w );
 
		else
 
			dPidt +=  complex_PijAj( (*w)->C2(), (*w)->C1(), *w );
 
	}*/
 
	
 
	// production of PIN depends on auxin concentration
 
	dPidt +=  (c->AtBoundaryP()?par->pin_prod_in_epidermis:par->pin_prod) * c->Chemical(0) - c->Chemical(1) * par->pin_breakdown;
 
	
 
	// no PIN production in SAM
 
	if (c->Boundary() == CellBase::SAM) {
 
			dchem[1]=0.;
 
		dchem[0]= - par->sam_auxin_breakdown * c->Chemical(0);
 
	} else {
 
		
 
		dchem[1] = dPidt;
 
		
 
		
 
		// source of auxin
 
		dchem[0] = par->aux_cons - par->aux_breakdown * c->Chemical(0);
 
		
 
	}
 
	
 
	
 
	
 
}
 

	
 

	
 
Q_EXPORT_PLUGIN2(auxingrowthplugin, AuxinGrowthPlugin)
src/build_models/meinhardtplugin.cpp
Show inline comments
 
@@ -96,41 +96,35 @@ void MeinhardtPlugin::CelltoCellTranspor
 

	
 
    // Passive fluxes (Fick's law)
 
    for (int c=0;c<NChem();c++) {
 
		double phi = w->Length() * ( par->D[c] ) * ( w->C2()->Chemical(c) - w->C1()->Chemical(c) );
 
		dchem_c1[c] += phi; 
 
		dchem_c2[c] -= phi;
 
	}
 
   
 

	
 
}
 

	
 
void MeinhardtPlugin::WallDynamics(Wall *w, double *dw1, double *dw2) {
 
  w = NULL;
 
	for (int c = 0;c<NChem();c++) {
 
		dw1[c] = 0.; dw2[c] = 0.;
 
    }
 
}
 

	
 
void MeinhardtPlugin::CellDynamics(CellBase *c, double *dchem) {
 

	
 
	double Y = c->Chemical(0);
 
	double A = c->Chemical(1);
 
	double H = c->Chemical(2);
 
	double S = c->Chemical(3);
 
	//double expansin = c->Chemical(4);
 

	
 
	
 
	
 
    dchem[0] = ( par->d * A - par->e * Y + Y*Y/(1 + par->f * Y*Y ) );
 
	dchem[1] = ( par->c * A*A*S/H - par->mu * A + par->rho0*Y );
 
	dchem[2] = ( par->c * A*A*S - par->nu*H + par->rho1*Y );
 
	dchem[3] = ( par->c0 - par->gamma*S - par->eps * Y * S );
 
	//dchem[4] = ( -par->expansindecay * expansin );
 
	//for (int i=0;i<4;i++) { cerr << "[ " << dchem[i] << " ]"; } cerr << endl;
 
	 
 
//	cerr << "Chemicals: "; for (int i=0;i<NChem();i++) { cerr << c->Chemical(i) << " "; } cerr << endl; 
 
	
 
// test:	dchem[0] = 0.01 * c->Chemical(0) * ( 1. - c->Chemical(0));
 
}
 

	
 

	
 
Q_EXPORT_PLUGIN2(meinhardtplugin, MeinhardtPlugin)
src/build_models/testplugin.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
 
 *  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.
 
 *
 
 */
 

	
 
#ifndef _TESTPLUGIN_H_
 
#define _TESTPLUGIN_H_
 

	
 
#include <QObject>
 
#include <QtGui>
 
#include <QString>
 
#include "../simplugin.h"
 

	
 

	
 
class TestPlugin : public QObject, SimPluginInterface {
 
	Q_OBJECT
 
	Q_INTERFACES(SimPluginInterface);
 

	
 
public:
 
	virtual QString ModelID(void) { return QString( "Test model" ); }
 
	
 
	// Executed after the cellular mechanics steps have equillibrized
 
	virtual void CellHouseKeeping (CellBase *c);
 
	// Differential equations describing transport of chemicals from cell to cell
 
	virtual void CelltoCellTransport(Wall *w, double *dchem_c1, double *dchem_c2);
 
    
 
	// Differential equations describing chemical reactions taking place at or near the cell walls
 
	// (e.g. PIN accumulation)
 
	virtual void WallDynamics(Wall *w, double *dw1, double *dw2);
 
	
 
	// Differential equations describing chemical reactions inside the cells
 
	virtual void CellDynamics(CellBase *c, double *dchem);
 
	
 
	// to be executed after a cell division
 
	virtual void OnDivide(ParentInfo *parent_info, CellBase *daughter1, CellBase *daughter2);
 
	
 
	// to be executed for coloring a cell
 
	virtual void SetCellColor(CellBase *c, QColor *color);	
 
	// return number of chemicals
 
	virtual int NChem(void) { return 0; }
 
};
 

	
 

	
 

	
 

	
 
#endif
src/canvas.cpp
Show inline comments
 
@@ -142,298 +142,215 @@ void FigureEditor::Save(const char *fnam
 
    
 
    render(painter);
 
    
 
    image->save(QString(fname),format);
 
    delete painter;
 
    delete image;
 
}
 

	
 
//void FigureEditor::contentsMousePressEvent(QMouseEvent* e)
 
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
 
  
 

	
 
  /*  if (dynamic_cast<Main *>(parent())->RotationModeP()) {
 
  // if in rotation mode, exit it upon a mouse click
 
  dynamic_cast<Main *>(parent())->ExitRotationMode();
 
  }*/
 
  
 
  QList<QGraphicsItem *> l=scene()->items(p);
 

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

	
 

	
 
    /*  if (rotation_mid_point) {
 
    
 
    // calculate rotation angle alpha
 
    QPointF q_v1 = intersection_line->line().p2();
 
    - intersection_line->line().p1();
 
    QPointF q_v2 = angle_line->line().p2();
 
    - angle_line->line().p1();
 
    
 
    Vector v1(q_v1.x(),q_v1.y());
 
    Vector v2(q_v2.x(),q_v2.y());
 
    
 
    cerr << "v1 = " << v1 << endl;
 
    cerr << "v2 = " << v2 << endl;
 
    
 
    
 
    rot_angle = v1.SignedAngle(v2);
 
    cerr << "Angle is " << rot_angle << endl;
 
    
 
    const QPointF &q_c(angle_line->line().p1());
 
    Vector center = Vector(q_c.x(), q_c.y()) / Cell::Factor() - Cell::Offset();
 
    
 
    cerr << "Center is " << center << endl;
 
    
 
    mesh.Rotate(rot_angle, center);
 
    delete angle_line;
 
    angle_line=0;
 
    delete intersection_line;
 
    intersection_line=0;
 
    
 
    viewport()->setMouseTracking( FALSE );
 
    dynamic_cast<Main *>(parent())->Plot();
 
    
 
    
 
    return;
 
    
 
    }*/
 
  
 
   
 
    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) {
 
      /*if ( (*it)->rtti() == imageRTTI ) {
 
	ImageItem *item= (ImageItem*)(*it);
 
	if ( !item->hit( p ) )
 
	continue;
 
	}*/
 
      #ifdef QDEBUG
 
      qDebug() << typeid(**it).name() << endl;
 
      #endif
 

	
 
      if ( !strcmp(typeid(**it).name(),"8NodeItem")) {
 
	//moving = dynamic_cast<NodeItem*>(*it);
 
	//moving = *it;
 
	//moving_start = p;
 
      
 
	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());      
 
	  //static int old_stride=100;
 
	  //if (!c.Source()) {
 
	  /* if (!c.Source()) {
 
	     c.SetChemical(0,par.cellsource);
 
	     //flag=true;
 
	     //c.SetSource(0,par.cellsource);
 
	     //c.Fix();
 
	     //cerr << "Setting source\n";
 
			
 
	     } else { 
 
	     //c.UnsetSource();
 
	     cerr << "Unsetting source\n";
 
	     } */
 
	  // 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::contentsMouseMoveEvent(QMouseEvent* e)
 
void FigureEditor::mouseMoveEvent(QMouseEvent* e)
 
{
 

	
 
  // User choose "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() );
 
    
 
    //viewport()->setMouseTracking( FALSE );
 
    dynamic_cast<Main *>(parent())->Plot(0);
 
	  FullRedraw();
 
    return;
 
  }
 
  if ( moving ) {
 
    //QPoint p = matrix().inverted().map(e->pos());
 

	
 
    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 (angle_line) {
 

	
 
    QPointF sp = angle_line -> line().p1(); // startpoint
 
    //QPointF ep = matrix().inverted().map(e->pos()); // endpoint
 
    QPointF ep = mapToScene(e->pos()); // endpoint
 
    angle_line -> setLine( QLineF(sp, ep) ); 
 
    scene()->update();
 
  
 
    } else { */
 
    
 
  if ( intersection_line ) {
 
    
 
    QPointF sp = intersection_line -> line().p1(); // startpoint
 
    //QPointF ep = matrix().inverted().map(e->pos()); // endpoint
 
    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 = matrix().inverted().map(e->pos()); // endpoint
 
      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();
 
    
 
      // Mesh &m(intersected_cells.front()->getCell().getMesh());
 
      NodeSet *node_set = new NodeSet;
 
      
 
      for (vector<CellItem *>::iterator it = intersected_cells.begin();
 
	   it != intersected_cells.end();
 
	   it++) {
 
      
 
	//(*it)->Mark();
 
	(*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 &m(intersected_cells.front()->getCell().getMesh());
 
	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);
 
	}
 

	
 

	
 
@@ -444,86 +361,76 @@ void FigureEditor::mouseReleaseEvent(QMo
 
	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
 
	qDebug() << "NodeSet of cutting line: " << *node_set << endl;
 
	#endif
 
    }
 
  } else 
 
    if (e->button()==Qt::RightButton) {
 
      
 
      if (intersection_line /* && !angle_line*/) {
 
	
 
	//QPointF p = matrix().inverted().map(e->pos());
 
	QPointF p = mapToScene(e->pos());
 
	QPointF sp = intersection_line->line().p1();
 
	
 
	viewport()->setMouseTracking( TRUE );
 
	/* angle_line = new QGraphicsLineItem( 0, scene() );
 
	angle_line->setPen( QPen( QColor("Blue"), 3, Qt::DashLine ) );
 
	angle_line->setLine( QLineF(sp, p) );
 
	angle_line->setZValue( 100 );
 
	angle_line->show();
 
	*/
 
      } 
 
            
 
    }
 
}
 

	
 

	
 
// 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
 
@@ -534,216 +441,169 @@ NodeItem *FigureEditor::selectedNodeItem
 
    }
 
  }
 
  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)
 
	   
 
	  //canvas(c)
 
{
 
  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("&Fill canvas", this, SLOT(init()), Qt::CTRL+Qt::Key_F);
 

	
 
	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->insertItem("&New view", this, SLOT(newView()), Qt::CTRL+Qt::Key_N);
 

	
 
   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->insertItem("Read &parameters", this, SLOT(readPars()));
 
  //file->insertItem("&Write parameters", this, SLOT(savePars()));
 
	
 
	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 );
 
  //  edit->insertItem("Add &Polygon", this, SLOT(addPolygon()), ALT+Key_P);
 
  //edit->insertItem("Add &Line", this, SLOT(addLine()), ALT+Key_L);
 
  running = false;
 
	paused_id = run->insertItem("&Simulation paused", this, SLOT(togglePaused()), Qt::Key_S);
 
  run->setItemChecked(paused_id, FALSE);
 

	
 
  //run->insertItem("&Divide Cell", this, SLOT(Divide()), Qt::CTRL+Qt::Key_D);
 
 // run->insertItem("&Restart Simulation", this, SLOT(RestartSim())); 
 
  menu->insertItem("&Run", run);
 
  
 
  view = new Q3PopupMenu( menu );
 
  //view->insertItem("&Enlarge", this, SLOT(enlarge()), SHIFT+CTRL+Key_Plus);
 
  //view->insertItem("Shr&ink", this, SLOT(shrink()), SHIFT+CTRL+Key_Minus);
 
	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);
 
  //view->insertItem("Cell monitor", this, SLOT(cellmonitor()));
 

	
 
  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);
 
 	view->insertSeparator();
 
	  only_boundary_id = view->insertItem("Show only leaf &boundary", this, SLOT(toggleLeafBoundary()));
 
  //only_boundary_id = view->insertItem("Show only leaf &boundary", 0,0);
 
	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 );
 
  /* dbf_id = options->insertItem("Double buffer", this, SLOT(toggleDoubleBuffer()));
 
     options->setItemChecked(dbf_id, TRUE);*/
 
  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(help()) ); //, Key_F1);
 
  //help->insertItem( "What's &This", this , SLOT(whatsThis()), SHIFT+Key_F1);
 
  menu->insertItem("&Help",helpmenu);
 
  //QSlider *flux_arrow_slider = new QSlider( 0, 10000, 1, 100, Qt::Horizontal, this, "flux arrow size");
 
  //QSpinBox *stride  = new QSpinBox( 1, 1000, 1, this, "stride");
 
  
 
	    
 
  //QGridLayout *controlgrid = new QGridLayout( this, 1, 2, 10);
 
  // 2x1, 10 pixel border
 
  
 
  //controlgrid->addWidget( stride, 0, 0);
 
  //controlgrid->addWidget( flux_arrow_slider, 0, 1);
 
  //controlgrid->setColStretch( 1, 10 );
 
  
 
  
 
  //flux_arrow_size = 1.;
 
  //flux_arrow_slider -> setMinimumSize( 200,50);
 
  //connect( flux_arrow_slider, SIGNAL( valueChanged( int ) ), this, SLOT( setFluxArrowSize(int) ) );
 
  
 
  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;
 
	
 
	// A little bit of PSB/CWI decoration ;-)
 
	/*dockwindow = new Q3DockWindow();
 
	addDockWindow(dockwindow);
 
	QLabel *viblab = new QLabel; viblab->setPixmap(QPixmap(cwi_xpm));
 
	QString virtleafstring("<h1>The Virtual Leaf</h1>\n<center><b>Model:</b> <i>%1</i></center>");
 
	QLabel *virtleaf = new QLabel(virtleafstring.arg(mesh.ModelID()));
 
	QLabel *psblab = new QLabel; psblab->setPixmap(QPixmap(PSB_xpm));
 
	dockwindow->setHorizontalStretchable(true);
 
	dockwindow->boxLayout()->addWidget(viblab);//,Qt::AlignLeft);
 
	dockwindow->boxLayout()->addStretch();
 
	dockwindow->boxLayout()->addWidget(virtleaf);//, Qt::AlignHCenter);
 
	dockwindow->boxLayout()->addStretch();
 
	dockwindow->boxLayout()->addWidget(psblab);//, Qt::AlignRight);*/
 
	//QString virtleafstring("<h1>The Virtual Leaf</h1>\n<center><b>Model:</b> <i>%1</i></center>");
 
	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);
 
  
 
@@ -762,131 +622,121 @@ Main::~Main()
 

	
 
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() {
 
  
 
  // bool timer_active;
 
  /* if (timer_active=timer->isActive())
 
     imer->stop();*/
 
  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();
 
  /* if (timer_active)
 
     timer->start( 0 );*/
 
  
 
}
 

	
 

	
 
void Main::saveStateXML() {
 
  
 
   
 
  //   bool timer_active;
 
  //   if (timer_active=timer->isActive())
 
  //     timer->stop();
 
  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() {
 
  
 
   
 
  //   bool timer_active;
 
  //   if (timer_active=timer->isActive())
 
  //     timer->stop();
 
  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);
 
		
 
@@ -910,71 +760,69 @@ void Main::readPrevStateXML() {
 
    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("Succesfully read leaf from file %1. Time is %2 h.\n").arg(currentFile).arg(mesh.getTimeHours().c_str());
 
    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() {
 
  
 
@@ -1060,244 +908,173 @@ 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
 
    
 
//     try {
 
//       mesh.XMLRead((const char *)fileName);
 
//       currentFile =  fileName;
 
//     } catch (const char *error_message) {
 
//       QMessageBox mb( "Read leaf from XML file",
 
// 		      QString(error_message),
 
// 		      QMessageBox::Critical,
 
// 		      QMessageBox::Ok | QMessageBox::Default,
 
// 		      QMessageBox::NoButton,
 
// 		      QMessageBox::NoButton);
 
//       mb.exec();
 
//       return readStateXML(); // user can try again
 
//     }
 
    
 
//     Vector bbll,bbur;
 
//     mesh.BoundingBox(bbll,bbur);
 
    
 
//     //FitLeafToCanvas();
 
//     Plot();
 
  }
 
}
 

	
 

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

	
 
void Main::help()
 
{
 
  static QMessageBox* about = new QMessageBox
 
    ( "About",
 
      "<h3>Virtual Leaf</h3>"
 
      "<p>"
 
      "Leaf growth computer model <br>"
 
      "(c) 2005-2007, Roeland Merks <br>"
 
      "VIB Department Plant Systems Biology <br>"
 
	 "Ghent, Belgium <br>"
 
      "(c) 2008-2009, Roeland Merks <br>"
 
      "CWI/NCSB, Amsterdam, Netherlands <br>"
 
      "Pilot release for WUR/Biometris, 21-10-2009 <br>", 
 
      QMessageBox::Information, 1, 0, 0, this, 0, FALSE );
 
  about->setButtonText( 1, "Dismiss" );
 
  about->show();
 
}
 

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

	
 
/* void Main::toggleDoubleBuffer()
 
{
 
  bool s = !options->isItemChecked(dbf_id);
 
  options->setItemChecked(dbf_id,s);
 
  canvas.setDoubleBuffering(s);
 
}
 
*/
 
  void Main::toggleShowCellCenters()
 
  {
 
    //bool s = !view->isItemChecked(com_id);
 
    //view->setItemChecked(com_id,s);
 
    Plot();
 
  }
 

	
 
  void Main::toggleShowWalls()
 
  {
 
    //bool s = !view->isItemChecked(cell_walls_id);
 
    //view->setItemChecked(cell_walls_id,s);
 
    Plot();
 
  }
 
void Main::toggleShowApoplasts()
 
{
 
    Plot();
 
}
 
  void Main::toggleShowNodes()
 
  {
 
    //bool s = !view->isItemChecked(mesh_id);
 
    //view->setItemChecked(mesh_id,s);
 
    Plot();
 
  }
 

	
 
  void Main::toggleNodeNumbers(void) {
 
  
 
    //bool s = !view->isItemChecked(node_number_id);
 
    //view->setItemChecked(node_number_id,s);
 
    Plot();
 
  }
 

	
 
  void Main::toggleCellNumbers(void) {
 
  
 
    //bool s = !view->isItemChecked(cell_number_id);
 
    //view->setItemChecked(cell_number_id,s);
 
    Plot();
 
  }
 

	
 
  void Main::toggleCellAxes(void) {
 
  
 
    //bool s = !view->isItemChecked(cell_axes_id);
 
    //view->setItemChecked(cell_axes_id,s);
 
    Plot();
 
  }
 

	
 
  void Main::toggleCellStrain(void) {
 
  
 
    //bool s = !view->isItemChecked(cell_strain_id);
 
    //view->setItemChecked(cell_strain_id,s);
 
    Plot();
 
  }
 

	
 
  void Main::toggleShowFluxes(void) {
 
  
 
    //bool s = !view->isItemChecked(fluxes_id);
 
    //view->setItemChecked(fluxes_id,s);
 
    Plot();
 
  }
 

	
 
  void Main::toggleShowBorderCells()
 
  {
 
    //bool s = !view->isItemChecked(border_id);
 
    //view->setItemChecked(border_id,s);
 
  void Main::toggleShowBorderCells(){
 
    Plot();
 
  }
 

	
 
void Main::toggleHideCells(void) {
 
	Plot();
 
	editor->FullRedraw();
 
}
 
  void Main::toggleMovieFrames()
 
  {
 
    //bool s = !view->isItemChecked(movie_frames_id);
 
    //view->setItemChecked(movie_frames_id,s);
 
  }
 
  void Main::toggleMovieFrames(){}
 

	
 
  void Main::toggleLeafBoundary(){}
 

	
 
  void Main::toggleLeafBoundary()
 
  {
 
    //bool s = !view->isItemChecked(only_boundary_id);
 
    //view->setItemChecked(only_boundary_id,s);
 
  }
 

	
 
  void Main::toggleDynCells()
 
  {
 
    //bool s = !options->isItemChecked(dyn_cells_id);
 
    //options->setItemChecked(dyn_cells_id,s);
 
  }
 

	
 

	
 
  void Main::toggleDynCells() {}
 
  
 
  void Main::startSimulation(void) {
 
    //run->setItemChecked(paused_id, false);
 
    timer->start( 0 );
 
    statusBar()->message("Simulation started");
 
    running = true;
 
  }
 

	
 
  void Main::stopSimulation(void) {
 
    //run->setItemChecked(paused_id, true);
 
    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.resize(canvas.width()*4/3, canvas.height()*4/3);
 
    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::scrollBy(int dx, int dy) {
 
    editor->scrollBy(dx,dy);
 
    }*/
 

	
 
  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()
 
  {
 
@@ -1344,112 +1121,48 @@ void Main::toggleHideCells(void) {
 
    }
 
  }
 

	
 

	
 
  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::SaveToGifAnim(void) {
 
  
 
    if (gifanim) {
 
    
 
    QPixmap image(canvas.width(), canvas.height());
 
    QPainter im(&image);
 
    
 
    
 
    canvas.drawArea(QRect(0,0,canvas.width(),canvas.height()),&im,FALSE);
 
    QFile conversionpipe;
 
    conversionpipe.open ( IO_WriteOnly, popen("pngtopnm | ppmtogif > tmp.gif", "w") );
 
    image.save( &conversionpipe, "PNG");
 
    conversionpipe.close();
 
    
 
    QFile readconvertedimage("tmp.gif");
 
    readconvertedimage.open(IO_ReadOnly);
 
    int c;
 
    while ( (c=readconvertedimage.getch())!=-1) {
 
    gifanim->putch(c);
 
    }
 
    }
 
    }*/
 

	
 
  /* void Main::StartGifAnim(QString fname) {
 
  
 
  if (gifanim) {
 
  QMessageBox::information( this, "Animation",
 
  "Already making another animation."
 
  "Please end it and try again.",
 
  QMessageBox::Ok );
 
  } else {
 
    
 
  QString cmdline("gifsicle --multifile - > ");
 
  cmdline += fname;
 
    
 
  gifanim = new QFile;
 
  gifanim->open( IO_WriteOnly, 
 
  popen((const char *)cmdline, "w") );
 
    
 
  */   /* QStringList cmdline;
 
	  cmdline << "gifsicle" << "--multifile" << "-";
 
	  gifanim = new QProcess( cmdline );
 
       
 
	  cmdline.clear();
 
	  cmdline << "pngtopnm";
 
	  pngtopnm = new QProcess( cmdline );
 
	  pngtopnm->start();
 
       
 
	  cmdline.clear();
 
	  cmdline << "ppmtogif";
 
	  ppmtogif = new QProcess( cmdline );
 
	  ppmtogif->start();*/
 
       /*  }
 

	
 
       }*/
 

	
 
       /*void Main::EndGifAnim(void) {
 
  
 
       if (gifanim)
 
       gifanim->close();
 

	
 
       }*/
 

	
 

	
 
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();
 
@@ -1474,83 +1187,77 @@ void Main::FitLeafToCanvas(void) {
 
  
 
  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);
 
}
 

	
 
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();
 
	
 
  //  repaint();
 
}
 

	
 
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();
 
	
 
	//  repaint();
 
}
 

	
 
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();
 
	
 
	//  repaint();
 
}
 

	
 
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);
 

	
src/canvas.h
Show inline comments
 
@@ -54,51 +54,48 @@
 

	
 
#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 contentsMousePressEvent(QMouseEvent*);
 
  void contentsMouseMoveEvent(QMouseEvent*);
 
  void contentsMouseReleaseEvent(QMouseEvent*);*/
 
  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;
 
@@ -113,77 +110,70 @@ class Main : public Q3MainWindow, 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 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 Save(const char *fname, const char *format);
 
  /*void StartGifAnim(QString fname);
 
    void SaveToGifAnim(void);
 
    void EndGifAnim(void);*/
 
    
 
  void FitCanvasToWindow();
 
  void FitLeafToCanvas(void);
 

	
 

	
 
  public slots:
 

	
 
  void help();
 
  void TimeStepWrap();
 
  //void scrollBy(int dx, int dy);
 
  void togglePaused();
 
  void setFluxArrowSize(int size);
 
  //void Divide(void);
 
  void RestartSim(void);
 
  //void toggleDoubleBuffer(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 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()));
 
    }
 
  
 
  }
 
  void ExitRotationMode(void) { 
 
    UserMessage("Exited rotation mode.",2000);
 

	
 
    options->setItemChecked(rotation_mode_id, false); 
 
@@ -193,78 +183,70 @@ class Main : public Q3MainWindow, public
 

	
 
  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 cellmonitor() { */
 
/*     PlotDialog *plot = new PlotDialog(this); */
 
/*     cerr << "Attempting to launch a cell monitor\n"; */
 
/*   } */
 
  
 
  //void addPolygon();
 
  //void addLine();
 

	
 
  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;
 
  //QCanvas& canvas;
 
  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 tooltips_id; // help -> Show Cell Info
 
  int hide_cells_id; // view->Hide Cells
src/cell.cpp
Show inline comments
 
@@ -73,52 +73,49 @@ void Cell::DivideOverAxis(Vector axis) {
 
	// ->  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);
 
			
 
		} // else {
 
		//       //cerr << "cross.z * prev_cross_z = " << cross.z * prev_cross_z << endl;
 
		//     }
 
		
 
		}		
 
		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
 
	}
 
@@ -199,94 +196,48 @@ void Cell::Apoptose(void) {
 
			// 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);
 
			}
 
		}
 
	}
 
	
 
	
 
	
 
	/*
 
	 // correct boundary polygon if this cell touches the boundary
 
	 
 
	 // find the first living boundary node after a dead node
 
	 bool node_found = false;
 
	 for (list<Node *>::iterator n=nodes.begin();
 
	 n!=nodes.end();
 
	 n++) {
 
	 
 
	 Node &no(*(*n));
 
	 
 
	 if (no.DeadP()) {
 
	 
 
	 list<Node *>::iterator first_node = n; 
 
	 if (++next_node == nodes.end()) first_node=nodes.begin();
 
	 
 
	 if (!(*(*first_node)).DeadP() && ((*first_node)->boundary)) {
 
	 node_found=true;
 
	 break;
 
	 }
 
	 
 
	 }
 
	 }
 
	 
 
	 // locate it in the boundary_polygon
 
	 if (node_found) {
 
	 list<Node *>::iterator insert_it = find(mesh->boundary_polygon->nodes.begin(),
 
	 mesh->boundary_polygon->nodes.end(),
 
	 ++first_node);
 
	 if (insert_it!=owners.end()) {
 
	 
 
	 if (insert_it==owners.end()) insert_it=owners.begin();
 
	 
 
	 for (list<Node *>::iterator n=insert_it;
 
	 n!=nodes.end();
 
	 n++) {
 
	 
 
	 Node &no(*(*n));
 
	 
 
	 mesh->boundary_polygon->nodes.insert(
 
	 
 
	 }
 
	 
 
	 
 
	 }
 
	 } */
 
	// 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()) 
 
@@ -343,50 +294,48 @@ bool Cell::DivideOverGivenLine(const Vec
 
	
 
	#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;
 
		
 
		/* double intersec_x = v1.x + ua*(v2.x-v1.x);
 
		 double intersec_y = v1.y + ua*(v2.y-v1.y);*/
 
		
 
		//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; 
 
@@ -412,64 +361,61 @@ void Cell::DivideWalls(ItList new_node_l
 
	
 
	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;
 
	//extern double auxin_account;
 
	//auxin_account += daughter->chem[0];
 
	
 
	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;
 
//	daughter->BaseArea()  = base_area;
 
	
 
	
 
	// 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
 
@@ -596,53 +542,48 @@ void Cell::DivideWalls(ItList new_node_l
 
			
 
			// 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
 
				/* (new_node_ind[i])->boundary = true;
 
				 (new_node_ind[i])->sam = true;
 
				 boundary_touched_flag = true;
 
				 boundary = SAM;
 
				 daughter->boundary = SAM;*/
 
			}
 
			
 
			// 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
 
@@ -785,93 +726,81 @@ void Cell::DivideWalls(ItList new_node_l
 
			
 
			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() << "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];
 
					}
 
					
 
					
 
					//new_wall->ResetTransporterConcentrations(orig_length);
 
					//(*w)->ResetTransporterConcentrations(orig_length);
 
					
 
					// reset the transporter concentrations
 
					
 
					
 
					/*	  new_wall->SetLength();
 
					 new_wall->CorrectLength(orig_length);
 
					 
 
					 (*w)->SetLength();
 
					 (*w)->CorrectLength(orig_length);*/
 
					
 
					// 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
 
@@ -980,53 +909,50 @@ void Cell::DivideWalls(ItList new_node_l
 
	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 { // if fix_cellwall is true, that is if we are cutting off
 
			// part of a leaf to make a nice initial condition, we also want to make it part of the boundary
 
			//node->boundary = true;
 
		else {
 
			node->fixed = true;
 
			//node->sam = 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();
 
@@ -1079,127 +1005,119 @@ void Cell::DivideWalls(ItList new_node_l
 
	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]);
 
		}
 
	}
 
	
 
	//neighbors.push_back( daughter );
 
	//daughter->neighbors.push_back( this );
 
	
 
	
 
	//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);
 
	// wall->OnWallInsert();
 
	//daughter->OnDivide();
 
	
 
	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++) {
 
		
 
		//if ((*i)->Fixed()) return; // commented out 01/12/05
 

	
 
		for (list<Neighbor>::const_iterator n=(*i)->owners.begin();
 
			 n!=(*i)->owners.end();
 
			 n++) {
 
			
 
			if (n->getCell()!=this) {
 
				//if (!(m->getNode(n->nb1).Fixed() && m->getNode(n->nb2).Fixed())) {
 
				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());
 
	}
 
@@ -1209,64 +1127,48 @@ double Cell::Displace(double dx, double 
 
		 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;
 
		
 
		/*vector<double> area1;
 
		 vector<double> area2;
 
		 m->ExtractFromCells( mem_fun_ref(&Cell::Area), back_inserter(area1) );
 
		 m->ExtractFromCells( mem_fun_ref(&Cell::CalcArea), back_inserter(area2));
 
		 vector<double>::iterator i=area1.begin();
 
		 vector<double>::iterator j=area2.begin();
 
		 int c=0;
 
		 for (;
 
		 i!=area1.end();
 
		 (i++, j++)) {
 
		 if ( (*i-*j) > 1e-10) {
 
		 cerr << c++ << " " << *i << " " << *j << endl;
 
		 abort();
 
		 }
 
		 }*/
 
		
 
	} 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++) {
 
		
 
@@ -1330,50 +1232,48 @@ bool Cell::SelfIntersect(void) {
 
			
 
			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;
 
			
 
			/* double intersec_x = v1.x + ua*(v2.x-v1.x);
 
			 double intersec_y = v1.y + ua*(v2.y-v1.y);*/
 
			
 
			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/
 
	
 
@@ -1405,97 +1305,91 @@ bool Cell::MoveSelfIntersectsP(Node *mov
 
		 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;
 
			
 
			/* double intersec_x = new_pos.x + ua*(neighbor_of_moving_node[j].x-new_pos.x);
 
			 double intersec_y = new_pos.y + ua*(neighbor_of_moving_node[j].y-new_pos.y);*/
 
			
 
			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;
 
		
 
		/* double intersec_x = v1.x + ua*(v2.x-v1.x);
 
		 double intersec_y = v1.y + ua*(v2.y-v1.y);*/
 
		
 
		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();
 
@@ -1550,56 +1444,54 @@ void Cell::ConstructWalls(void) {
 
		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) {
 
			//walls. new Wall(*nb,*i,duplicates[0],duplicates[1]) );
 
			AddWall(  new Wall(*nb,*i,duplicates[0],duplicates[1]) );
 
			if (!duplicates[1]->BoundaryPolP()) {
 
				
 
				neighbors.push_back(duplicates[1]);
 
			}
 
		} else {
 
			//walls.push_back( new Wall(*nb,*i,duplicates[1],duplicates[0]) ); 
 
			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++) {
 
@@ -1703,194 +1595,117 @@ void Cell::Draw(QGraphicsScene *c, QStri
 
}
 

	
 

	
 
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;
 
		
 
		//QCanvasEllipse *item = new QCanvasEllipse( 10, 10, c);
 

	
 
		NodeItem *item = new NodeItem ( &(*i), c );
 
		//QGraphicsRectItem *item = new QGraphicsRectItem(-50, -50, 50, 50, 0, c);
 
		//disk->setBrush( QColor("IndianRed") );
 
		
 
		/*if (i->sam) {
 
		 item->setBrush( purple );
 
		 } else {
 
		 if (i->boundary) {
 
		 item->setBrush( deep_sky_blue );
 
		 } 
 
		 else {
 
		 item->setBrush( indian_red );
 
		 }
 
		 }*/
 
		item->setColor();
 
		
 
		/*(if (item->getNode().DeadP()) {
 
		 item->setBrush( QBrush (Qt::Dense6Pattern) );
 
		 }*/
 
		item->setZValue(5);
 
		item->show();
 
		item ->setPos(((offset[0]+i->x)*factor),
 
					  ((offset[1]+i->y)*factor) );
 
	}
 
	
 
}
 

	
 
void Cell::DrawIndex(QGraphicsScene *c) const {
 
	
 
	//  stringstream text;
 
	//     text << index;
 
	//     Vector centroid = Centroid();
 
	//     QCanvasText *number = new QCanvasText ( QString (text.str()), c );
 
	//     number->setColor( QColor(par.textcolor) );
 
	//     number->setZ(20);
 
	//     number->setFont( QFont( "Helvetica", par.cellnumsize, QFont::Bold) );
 
	//     number->show();
 
	//     number -> move((int)((offset[0]+centroid.x)*factor),
 
	// 		   (int)((offset[1]+centroid.y)*factor) );
 
	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->setTextFlags(Qt::AlignCenter);
 
	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 ),
 
				  ( (offset[1]+from.y)*factor ), 
 
				  ( (offset[0]+to.x)*factor ),
 
				  ( (offset[1]+to.y)*factor ) );
 
	line->setZValue(10);
 
	line->show();
 
	
 
}
 

	
 
void Cell::DrawStrain(QGraphicsScene *c) const {
 
  c = NULL; // assignment merely to obviate compilation warning
 
	MyWarning::warning("Sorry, Cell::DrawStrain temporarily not implemented.");
 
	/* Vector long_axis;
 
	double width;
 
	Length(&long_axis, &width);
 
	
 
	//cerr << "Length is "  << length << endl;
 
	long_axis.Normalise();
 
	Vector short_axis=long_axis.Perp2D();
 
    
 
	//  To test method "Strain" temporarily substitute "short_axis" for "strain" 
 
	Vector strain = Strain();
 
	//strain.Normalise();
 
	//static ofstream strainf("strain.dat");
 
	//strainf << strain.Norm() << endl;
 
	Vector centroid = Centroid();
 
	// Vector from = centroid - 0.5 * width * short_axis;
 
    // Vector to = centroid + 0.5 * width *short_axis;
 
	Vector from = centroid - 0.5 * strain;
 
	Vector to = centroid + 0.5 * strain;
 
	
 
	QGraphicsArrowItem *arrow = new QGraphicsArrowItem(0, c);
 
	arrow->setPen( QPen(QColor(par.arrowcolor),100) );
 
    
 
	arrow->setLine( ( (offset[0]+from.x)*factor ),
 
				   ( (offset[1]+from.y)*factor ), 
 
				   ( (offset[0]+to.x)*factor ),
 
				   ( (offset[1]+to.y)*factor ) );
 
	arrow->setZValue(10.);
 
	arrow->show();
 
	*/
 
}
 

	
 
// Draw connecting lines to neighbors
 
/*void Cell::DrawTriangles(QCanvas &c) {
 
 
 
 for (list<Neighbor>::const_iterator nb=nb_list.begin();
 
 nb!=nb_list.end();
 
 nb++) {
 
 QCanvasLine *line = new QCanvasLine(&c);
 
 line->setPen( QPen(QColor("black"),2) );
 
 line->setZ(2);
 
 
 
 line->setPoints((offset[0]+x)*factor,(offset[1]+y)*factor, 
 
 (offset[0]+nb->c->x)*factor,(offset[1]+nb->c->y)*factor);
 
 line->setZ(10);
 
 line->show();
 
 }
 
 
 
 }*/
 

	
 

	
 

	
 
void Cell::DrawFluxes(QGraphicsScene *c, double arrowsize)  {
 
	
 
	// get the mean flux through this cell
 
	//Vector vec_flux = ReduceWalls( mem_fun_ref( &Wall::VizFlux ), Vector() );
 
	Vector vec_flux = ReduceCellAndWalls<Vector>( PINdir );
 
	
 
	vec_flux.Normalise();
 
	
 
	vec_flux *= arrowsize;
 
	
 
	QGraphicsArrowItem *arrow = new QGraphicsArrowItem(0,c);
 
	
 
	Vector centroid = Centroid();
 
	Vector from = centroid - vec_flux/2.;
 
	Vector to = centroid + vec_flux/2.;
 
    
 
	
 
	arrow->setPen( QPen(QColor(par.arrowcolor),par.outlinewidth));
 
	arrow->setZValue(2);
 
	
 
	arrow->setLine( ( (offset[0]+from.x)*factor ),
 
				   ( (offset[1]+from.y)*factor ), 
 
				   ( (offset[0]+to.x)*factor ),
 
				   ( (offset[1]+to.y)*factor ) );
 
	arrow->setZValue(10);
 
	arrow->show();
 
	
 
}
 
@@ -1991,28 +1806,27 @@ void Cell::AddWall( Wall *w ) {
 
list<Wall *>::iterator Cell::RemoveWall( Wall *w ) {
 
	
 
	// remove wall from Mesh's list
 
	m->walls.erase(
 
				   find(
 
						m->walls.begin(), m->walls.end(),
 
						w )
 
				   );
 
	
 
	// remove wall from Cell's list
 
	return 
 
	walls.erase (
 
				 find( 
 
					  walls.begin(), walls.end(),
 
					  w )
 
				 );
 
	
 
}
 

	
 

	
 

	
 
void Cell::EmitValues(double t) {
 
	
 
	//  cerr << "Attempting to emit " << t << ", " << chem[0] << ", " << chem[1] << endl;
 
	//chem[3] = SumTransporters( 1 );
 
	emit ChemMonValue(t, chem);
 
	
 
}
src/cell.h
Show inline comments
 
@@ -70,52 +70,48 @@ public:
 
		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;
 
    }
 
    
 
    // return node "i"
 
    // wrapped around, i.e. node n==node 0
 
    // will not work if i < -nodes.size()
 
    //Node &getNode(int i) const;
 
    void DivideOverAxis(Vector axis); // divide cell over axis
 
    bool DivideOverGivenLine(const Vector v1, const Vector v2, bool wall_fixed = false, NodeSet *node_set = 0); // divide over the line (if line and cell intersect)
 
	
 
    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);
src/cellbase.cpp
Show inline comments
 
@@ -19,70 +19,62 @@
 
 *
 
 */
 

	
 
#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 "cond_operator.h"
 
#include "cellbase.h"
 
//#include "node.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"};
 

	
 
// These statics have moved to class "CellsStaticDatamembers"
 

	
 
//double CellBase::static_base_area = 0.;
 
//int CellBase::ncells=0;
 
//int CellBase::NChem()=0;
 

	
 
#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;
 
@@ -167,49 +159,49 @@ CellBase::CellBase(const CellBase &src) 
 
	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);
 
	//  QObject::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;
 
@@ -330,55 +322,48 @@ Vector CellBase::Centroid(void) const {
 
		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/=2.0;
 
	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;
 
}
 

	
 
/*Node &CellBase::getNode(list<Node *>::const_iterator i) const {
 

	
 
if (i==
 
	return m->getNode(i);
 
  }*/
 

	
 

	
 

	
 

	
 
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+= 
 
@@ -387,90 +372,79 @@ void CellBase::SetIntegrals(void) const 
 
			 (*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/=2.0;
 

	
 
	area = fabs(area)/2.0;
 
	
 
	/* intgrl_x/=6.;
 
	intgrl_y/=6.;
 
	
 
	intgrl_xx/=12.;
 
	intgrl_xy/=24.;
 
	intgrl_yy/=12.;*/
 
	
 
	
 
}
 

	
 
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";
 
	
 
	// Vector eigenvectors[2];
 
	// eigenvectors[0] = Vector(-(-ixx + iyy ) + rhs2, ixy, 0);
 
	// eigenvectors[1] = Vector(-(-ixx + iyy ) - rhs2, ixy, 0);
 
	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.;
 
@@ -510,459 +484,106 @@ double CellBase::CalcLength(Vector *long
 
		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";
 
	
 
	// Vector eigenvectors[2];
 
	// eigenvectors[0] = Vector(-(-ixx + iyy ) + rhs2, ixy, 0);
 
	// eigenvectors[1] = Vector(-(-ixx + iyy ) - rhs2, ixy, 0);
 
	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::NodeRemoved(int n) {
 
//   for (list<Node *>::iterator i=nodes.begin();
 
//        i!=nodes.end();
 
//        i++) {
 
//     if ((*i)->Index()>n) {
 
//       (*i)->index--;
 
//     }
 
//   }
 
// }
 

	
 
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!=(list<Wall *>::const_reverse_iterator)walls.rend();
 

	
 
		 wit!=walls.end();
 
		 wit++) {
 
		
 
		if ((*wit)->C1() != this) {
 
			neighbors.push_back((*wit)->C1());
 
		} else {
 
			neighbors.push_back((*wit)->C2());
 
		}
 
		
 
	}
 
	
 
	
 
	/*
 
	 for (list<CellBase *>::iterator e=neighbors.begin();
 
		  e!=neighbors.end();
 
		  e++) {
 
		 cerr << (*e)->Index() << " ";
 
		 if ((*e)->CellBase::BoundaryPolP()) {
 
			 cerr << " b ";
 
		 }
 
	 }
 
	 */
 
	// 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);
 
	
 
}
 

	
 
// CellBase constructs its neighbor list from its node lists
 
// Assumes, obviously, that the node lists are up to date
 
// (i.e. call ConstructConnections before calling this method)
 
// We'll keep this one private, anyway.
 
/* void CellBase::ConstructNeighborList(void) {
 

	
 
//  extern ofstream debug_stream;
 

	
 
neighbors.clear();
 

	
 
//  debug_stream << "Nodes: ";
 
//  copy(nodes.begin(),nodes.end(),ostream_iterator<Node>(debug_stream, " "));
 
//debug_stream << endl;
 

	
 
for (list<Node *>::const_iterator i=nodes.begin();
 
	 i!=nodes.end();
 
	 i++) {
 
    
 
    // collect all cells to which my nodes are connected on one list
 
    //transform((*i)->cells.begin(),(*i)->cells.end(), back_inserter(neighbors), mem_fun_ref(&Neighbor::CellBase));
 
	
 
    // index of next node 
 
    list<Node *>::const_iterator nn=i;
 
    ++nn;
 
    if (nn==nodes.end()) 
 
		nn=nodes.begin();
 
	
 
    //    debug_stream << "Node " << *i << ", Neighbor " << *nn << endl;
 
    // debug_stream << "Owners: ";
 
    //    copy((*i)->cells.begin(),(*i)->cells.end(),ostream_iterator<Neighbor>(debug_stream, " "));
 
    // debug_stream << endl;
 
    
 
    for (list<Neighbor>::const_iterator nb=(*i)->owners.begin();
 
		 nb!=(*i)->owners.end();
 
		 nb++) {
 
		
 
		// collect info about neighboring cells, not about myself
 
		if (nb->CellBase!=this) {
 
			
 
			// make sure the whole edge touches this putative neighbor
 
			// if (*nn == nb->nb1 || *nn == nb->nb2) {
 
			//walls.push_back( new Wall(*i,*nn,this,nb->CellBase) );
 
			//debug_stream << "Adding edge " << walls.back() << " to CellBase " << index << endl;
 
			//}
 
			
 
			neighbors.push_back( nb->CellBase );
 
		} 
 
    }
 

	
 

	
 
}
 

	
 
neighbors.sort();
 

	
 
list<CellBase *>::iterator e=unique(neighbors.begin(),neighbors.end());
 

	
 
// iterator e point to the end of the subsequence of unique elements
 
// remove every thing that comes after it
 

	
 
neighbors.erase(e, neighbors.end());
 

	
 
// okay, now neighbors contains all neighbors of this CellBase, including itself
 

	
 
// A future optimization for the diffusion algorithm: now we list
 
// each of the edges of a (curved) CellBase boundary separately.  We
 
// could keep track just of the total length per CellBase boundary
 

	
 
// the following is not necessary anymore. Is
 
// checked at earlier stage
 
// // remove myself from the list
 
//   e = find(neighbors.begin(),neighbors.end(),index);
 
//   if (e!=neighbors.end())
 
//   neighbors.erase(e);
 
//    
 

	
 
// remove boundary_polygon from the list (CellBase identity <0 )
 
e=neighbors.begin();
 
at_boundary=false;
 
do { 
 
    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);
 

	
 

	
 
}*/
 

	
 

	
 
/*void Cell::print_nblist(void) const {
 
//  cerr << "{ ";
 

	
 
for (list<Neighbor>::const_iterator i=nb_list.begin();
 
	 i!=nb_list.end();
 
	 i++) {
 
	//    cerr << "(" << i->c->index << " " << i->Dij << ")";
 
	
 
}
 
//  cerr << "}" << endl;
 
}
 
*/
 

	
 

	
 
// Tests whether Cell p (given as Vector, remember that Cell is a
 
// Vector) is within polygon formed by nearest neighbor cells
 
// 
 
// Based on algorithm and code by Paul Bourke, see
 
// http://astronomy.swin.edu.au/~pbourke/geometry/insidepoly/
 
//
 
// Note: works for 2D only; projects everything on z=0;
 
/*
 
#define MIN(x,y) (x < y ? x : y)
 
#define MAX(x,y) (x > y ? x : y)
 
 */
 
/*bool Cell::CellInsidePolygonP(Vector &p)
 
{
 
    int counter = 0;
 
    double xinters;
 
    Vector p1,p2;
 
	
 
    //p1 = polygon[0];
 
    p1 = *(nb_list.begin()->c);
 
	
 
    int N=nb_list.size();
 
    list<Neighbor>::const_iterator nb=nb_list.begin();
 
	
 
    for (int i=1;i<=N;i++) {
 
		
 
		nb++;
 
		
 
		if (nb!=nb_list.end()) {
 
			p2 = *(nb->c);
 
		} else {
 
			p2 = *(nb_list.begin()->c);
 
		}
 
		
 
		if (p.y > MIN(p1.y,p2.y)) {
 
			if (p.y <= MAX(p1.y,p2.y)) {
 
				if (p.x <= MAX(p1.x,p2.x)) {
 
					if (p1.y != p2.y) {
 
						xinters = (p.y-p1.y)*(p2.x-p1.x)/(p2.y-p1.y)+p1.x;
 
						if (p1.x == p2.x || p.x <= xinters)
 
							counter++;
 
					}
 
				}
 
			}
 
		}
 
		p1 = p2;
 
    }
 
	
 
    if (counter % 2 == 0)
 
		return false;
 
    else
 
		return true;
 
	
 
}*/
 

	
 

	
 
/* // at new position cell should be able to "see" all polygon sides
 
bool Cell::NewPointValidP(Vector &p) {
 
	
 
	//int ninvtri=0;
 
	for (list<Neighbor>::const_iterator nb=nb_list.begin();
 
		 nb!=nb_list.end();
 
		 nb++) {
 
		
 
		Vector p1=*(nb->c); // first neighbor
 
		list<Neighbor>::const_iterator nextv=nb; nextv++;
 
		
 
		
 
		if (nextv==nb_list.end()) {
 
			if (Boundary()==None) {
 
				nextv=nb_list.begin();
 
			} else continue;
 
		}
 
		
 
		Vector p2=*(nextv->c);
 
		
 
		Vector v1=(p1-p);
 
		Vector v2=(p2-p1);
 
		
 
		Vector cross=v1*v2;
 
		//    //cerr << "[" << cross << "]" << endl;
 
		
 
		if (cross.z<0) {
 
			// One of the triangles has "inverted".
 
			//if (Boundary()==None || ninvtri) 
 
			return false;
 
			//else 
 
			// accept one "inverted" triangle
 
			//ninvtri++;
 
		}
 
	}
 
	return true;
 
    
 
}*/
 

	
 

	
 

	
 

	
 
// void Cell::CheckForDivision(void) {
 
//  //  if (/* Chemical(0)<0.4 && */ /* differentiated cells do not divide */ area > 2*base_area /* || Length()>50 */) {
 

	
 
//  if (area > par.rel_cell_div_threshold * base_area ) {
 
//    /* remark no longer valid? //m->IncreaseCellCapacityIfNecessary();
 
//      // Note that calling Divide as follows prevents trouble if cell
 
//      // vector is relocated */
 
//      Divide();
 
//  }
 
//}
 

	
 
/* void Cell::CheckForGFDrivenDivision(void) {
 
if (area > base_area && chem[0]>par.gf_div_threshold) {
 
    //int ind=index;
 
    if (index==1) return; // petiole does not divide
 
	
 
    // remark no longer valid?
 
    //m->IncreaseCellCapacityIfNecessary();
 
    // Note that calling Divide as follows prevents trouble if cell
 
    // vector is relocated
 
    Vector horizontal(1,0,0);
 
    Vector vertical(0,1,0);
 
    double r; 
 
    if ((r=RANDOM())>par.vertdivprob) {
 
		DivideOverAxis(horizontal);
 
    } else {
 
		cerr << "[" << r << "]";
 
		DivideOverAxis(vertical);
 
    }
 
}
 
}
 
*/
 

	
 

	
 

	
 
// return (a measure of) the strain of this cell
 
/*Vector CellBase::Strain(void) const {
 
	
 
	cerr << "Sorry, CellBase::strain currently not implemented" << endl;
 
	std::exit(1);
 
	
 
	// Reason: we do not want to include "Node" in the plugins (Node::target_length below), and we do need Strain anyway...
 
	
 
	
 
	// go over all wall elements of the cell
 
	 Vector Fvec;
 
	
 
	for (list<Node *>::const_iterator n=nodes.begin();
 
		 n!=nodes.end();
 
		 n++) {
 
		
 
		list<Node *>::const_iterator nn=n; nn++;
 
		if (nn==nodes.end()) nn=nodes.begin();
 
		
 
		Vector wall_element = *(*n) - *(*nn);
 
		
 
		// assume k=1 (Hooke's constant), for now
 
		double Fscal  = (Node::target_length - wall_element.Norm())/Node::target_length;
 
		
 
		
 
		Fvec += Fscal * wall_element.Normalised();
 
		
 
	}
 
	
 
	return Fvec; 
 
} */
 

	
 

	
 

	
 
/* void Cell::Flux(double *flux, double D)  {
 

	
 
// Algorithm according to Rudge & Haseloff 2005
 
// (will we need to take cell area into account?)
 
// For the time being, we don't: assume cell area is 
 
// mainly determined by vacuole.
 

	
 
// Currently implements Rolland-Lagan-Mitchison algorithm
 
// Rolland-Lagan and Prusinkiewicz, The Plant Journal (2005), 44, 854-865
 

	
 
// currently I only implemented passive, diffusive transport 
 
// active transport will be added later
 

	
 
// loop over cell edges
 

	
 
for (int c=0;c<Cell::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 < 0) continue;
 
    
 
	// calculate edge length 
 
	// (will later be updated during node displacement for efficiency)
 
	double edge_length = (m->nodes[i->n1]-m->nodes[i->n2]).Norm();
 
    
 
	// D is "background diffusion coefficient" (Rolland-Lagan)
 
	
 
	
 
	// flux depends on edge length and concentration difference */
 
	// i->phi = edge_length * ( /* i->D +*/ D ) * ( m->cells[i->c2].chem[0] - chem[0] );
 
	/*
 
	 if (m->cells[i->c1].index!=index) {
 
		 cerr << "Warning, bad cells boundary: " << m->cells[i->c1].index << ", " << index << endl;
 
	 }
 
	 
 
	 flux[0] += i->phi;
 
	 //double deltaD = par.alpha * (i->phi*i->phi) - par.gamma * i->D; // Note beta=0
 
	 //i->D += par.dt*deltaD; 
 
	 
 
	 //cerr << "[ i->D = " << i->D << ", deltaD = " << deltaD << "]";
 
	 //if (i->D > par.Dmax) i->D=par.Dmax;
 
	 
 
	 // first calculate all fluxes, we update diffusion coefficient afterwards.
 
	 
 
	 // cerr << "[ " << edge_length << ", " << m->cells[i->c2].chem[0] << " - " << chem[0] << "]";
 
	 
 
}
 

	
 

	
 
}
 
*/
 
	
 
	// 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;
 
		
 
		os << walls.size() << endl;
 
		/*for (list<Wall *>::const_iterator i=walls.begin();i!=walls.end(); i++) {
src/cellbase.h
Show inline comments
 
@@ -87,100 +87,96 @@ class CellBase :  public QObject, public
 
	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(const Vector &src); // not allowed (we cannot know to which mesh 
 
	/// the CellBase will belong...)
 
    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) {
 
	//area=0.;
 
	//length=0.;
 
      }
 
      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;
 
@@ -208,77 +204,74 @@ class CellBase :  public QObject, public
 
    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;
 
	}
 
	
 
	//Vector Strain(void) const;
 

	
 
    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 XFigPrint(std::ostream &os) const;
 
    
 
    void Dump(ostream &os) const;
 
   	
 
	QString printednodelist(void);
 
 
 
   // void OnDivide(ParentInfo &parent_info, CellBase &daughter);
 

	
 
    
 
    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;
 
    }
 
@@ -322,55 +315,48 @@ class CellBase :  public QObject, public
 
      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;
 
    }
 
    
 
	/* template<class Op> void LoopWalls(Op f) {
 
		for (list<Wall *>::const_iterator w=walls.begin();
 
			 w!=walls.end();
 
			 w++) {
 
			( **w)->f;
 
		}
 
	}*/
 
	
 
    //! 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();
 
      
 
@@ -442,51 +428,48 @@ protected:
 

	
 
    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;
 
	
 
    //double length;
 
    //Vector meanflux;
 
    //int valence;
 
    
 
    // 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) {
src/data_plot.cpp
Show inline comments
 
@@ -42,187 +42,149 @@ static const string _module_id("$Id$");
 

	
 
//
 
//  Initialize main window
 
//
 
DataPlot::DataPlot(QWidget *parent, const QString title, const QStringList curvenames ):
 
  QwtPlot(parent),
 
  d_interval(0),
 
  d_timerId(-1)
 
{
 

	
 
  // Number of curves is number of names given
 
  ncurves = curvenames.size();
 
  
 
  // allocate data and curves
 
  d_t = new double[PLOT_SIZE];
 
  d_x = new double *[ncurves];
 
  d_x[0] = new double[ncurves*PLOT_SIZE];
 
  for (int i=1;i<ncurves;i++) {
 
    d_x[i]=d_x[i-1]+PLOT_SIZE;
 
  }
 
  
 
  // Disable polygon clipping
 
  QwtPainter::setDeviceClipping(false);
 

	
 
  // We don't need the cache here
 
  //canvas()->setPaintAttribute(QwtPlotCanvas::PaintCached, false);
 
  //canvas()->setPaintAttribute(QwtPlotCanvas::PaintPacked, false);
 

	
 
  alignScales();
 
    
 
  //  Initialize data
 
  
 
  
 
  for (int i = 0; i< PLOT_SIZE; i++) {
 
    d_t[i] = 0.;     // time axis
 
  }
 

	
 
  for (int i=0;i<ncurves * PLOT_SIZE;i++) {
 
    d_x[0][i]=0.;
 
  }
 

	
 
  // Assign a title
 
  setTitle(title);
 
  insertLegend(new QwtLegend(), QwtPlot::BottomLegend);
 

	
 
  // Insert curves
 
  curves = new QwtPlotCurve[ncurves];
 
  for (int i=0;i<ncurves;i++) {
 

	
 
    curves[i].setTitle(curvenames[i]);
 
    curves[i].attach(this);
 
    curves[i].setPen(QPen(curvecolors[i]));
 
    QString col(curvecolors[i]);
 

	
 
    #ifdef QDEBUG
 
    qDebug() << "Curvecolor " << col.toStdString() << endl;
 
    #endif
 

	
 
    curves[i].setRawData(d_t, d_x[i], PLOT_SIZE);
 
  }
 
    
 
  // Axis 
 
  setAxisTitle(QwtPlot::xBottom, "Time");
 

	
 
  setAxisTitle(QwtPlot::yLeft, "Level");
 
  setAxisScale(QwtPlot::yLeft, 0, 10);
 
    
 
  //    setTimerInterval(0.0); 
 

	
 
  data_pos = 0;
 
  
 

	
 
  // open file for writing
 
  /* QString fname(title);
 
  fname.replace(QString(" "),QString());
 
  fname.append(".dat");
 
  std::cerr << "Writing to file " << fname.toStdString() << std::endl;
 
  
 
  datfile = new QFile(fname);
 
  if (!datfile->open(QIODevice::WriteOnly | QIODevice::Text))
 
    return;
 
  
 
  datstream.setDevice(datfile);
 
  */
 

	
 
}
 

	
 
DataPlot::~DataPlot(void) {
 
  delete[] d_t ;
 
  delete[] d_x[0];
 
  delete[] d_x;
 
  delete[] curves;
 
}
 
//
 
//  Set a plain canvas frame and align the scales to it
 
//
 
void DataPlot::alignScales()
 
{
 
    // The code below shows how to align the scales to
 
    // the canvas frame, but is also a good example demonstrating
 
    // why the spreaded API needs polishing.
 

	
 
    canvas()->setFrameStyle(QFrame::Box | QFrame::Plain );
 
    canvas()->setLineWidth(1);
 
    
 
    for ( int i = 0; i < QwtPlot::axisCnt; i++ )
 
    {
 
        QwtScaleWidget *scaleWidget = (QwtScaleWidget *)axisWidget(i);
 
        if ( scaleWidget )
 
            scaleWidget->setMargin(0);
 

	
 
        QwtScaleDraw *scaleDraw = (QwtScaleDraw *)axisScaleDraw(i);
 
        if ( scaleDraw )
 
            scaleDraw->enableComponent(QwtAbstractScaleDraw::Backbone, false);
 
    }
 
}
 

	
 
/* void DataPlot::setTimerInterval(double ms)
 
{
 
    d_interval = qRound(ms);
 

	
 
    if ( d_timerId >= 0 )
 
    {
 
        killTimer(d_timerId);
 
        d_timerId = -1;
 
    }
 
    if (d_interval >= 0 )
 
        d_timerId = startTimer(d_interval);
 
}
 
*/
 

	
 
//  Generate new values 
 
void DataPlot::AddValue(double t,double *x)
 
{
 

	
 
  //  std::cerr << "AddValue receives: " << t << ", " << y << ", " << z << std::endl;
 
  
 
  // Plot slowly fills up, then shifts to the left
 
  if ( data_pos >= PLOT_SIZE ) {
 
    
 
    for ( int j = 0; j < PLOT_SIZE - 1; j++ )
 
      d_t[j] = d_t[j+1];
 

	
 
    for ( int i=0;i<ncurves;i++) {
 
      for ( int j = 0; j < PLOT_SIZE - 1; j++ )
 
	d_x[i][j] = d_x[i][j+1];
 
    }
 
    data_pos = PLOT_SIZE - 1;
 
    
 
  } 
 

	
 
  d_t[data_pos] = t;
 

	
 
  // datstream << t;
 

	
 
  for ( int i=0;i<ncurves;i++) {
 
    curves[i].setRawData(d_t, d_x[i], data_pos);
 
    d_x[i][data_pos] = x[i];
 
    //datstream << " " << x[i];
 
  }
 
					       
 
  //datstream << "\n";
 
  
 
  setAxisScale(QwtPlot::xBottom, d_t[0], t);
 
  
 
  data_pos++;
 
  // update the display
 
  replot();
 
  
 

	
 
}
 

	
 

	
 
PlotDialog::PlotDialog(QWidget *parent, const QString title, const QStringList curvenames):
 
  QDialog(parent) 
 
{
 
  
 
  plot = new DataPlot(this,title,curvenames);
 
  
 
  plot->resize(400,300);
 
  
 
  show();
 

	
 
}
 

	
 
PlotDialog::~PlotDialog(void) {
 
  
src/data_plot.h
Show inline comments
 
@@ -21,66 +21,64 @@
 
 *
 
 */
 

	
 
#ifndef _DATA_PLOT_H_
 
#define _DATA_PLOT_H_
 

	
 
#include <QDialog>
 
#include <qwt_plot.h>
 
#include <iostream>
 
#include <QFile>
 
#include <QTextStream>
 
#include <qwt_plot_curve.h>
 
#include "curvecolors.h"
 

	
 
const int PLOT_SIZE = 1000; 
 

	
 
class DataPlot : public QwtPlot
 
{
 
    Q_OBJECT
 

	
 
public:
 
  DataPlot(QWidget *parent, const QString title, const QStringList curvenames);
 
  virtual ~DataPlot(void);
 
public slots:
 
    //    void setTimerInterval(double interval);
 
    void AddValue(double t, double *x);
 

	
 
private:
 
    void alignScales();
 

	
 
    double *d_t; 
 
    double **d_x; 
 

	
 
    int d_interval; // timer in ms
 
    int d_timerId;
 
    
 
    QwtPlotCurve *curves;
 
    int data_pos;
 
    int ncurves;
 
    
 
    CurveColors curvecolors;
 

	
 
 protected:
 
    // to write contents of DataPlot to a file
 
    QFile *datfile;
 
    QTextStream datstream;
 

	
 
};
 

	
 
class PlotDialog : public QDialog {
 

	
 
Q_OBJECT
 
 public:
 
  PlotDialog(QWidget *parent, const QString title, const QStringList curvenames);
 
  ~PlotDialog(void);
 
  public slots:
 
    //    void setTimerInterval(double interval);
 
  void AddValue(double t, double *x) {
 
    //std::cerr << "AddValue receives: " << t << ", " << y << ", " << z << std::endl;
 
    plot->AddValue(t,x);
 
  }
 
 private:
 
  DataPlot *plot;
 
};
 

	
 
#endif
src/flux_function.h
Show inline comments
 
/*
 
 *  flux_function.h
 
 *  VirtualLeaf
 
 *
 
 *  $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.
 
 *
 
 *  Created by Roeland Merks on 07-06-10.
 
 *  Copyright 2010 __MyCompanyName__. All rights reserved.
 
 *  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.
 
 *
 
 */
 

	
 

	
 
#ifndef _FLUX_FUNCTION_h_
 
#define _FLUX_FUNCTION_h_
 

	
 
// This header file defines a macro "SumFluxFromWalls" that attempts to hide this 
 
// horrendously confusing member function wrapper construct from VirtualLeaf's end users
 

	
 
// required format of flux_function is:
 
// double [model class name]::[function name](CellBase *this_cell, CellBase *adjacent_cell, Wall *w)
 
// e.g.:
 
// double MyModel::PINflux(CellBase *this_cell, CellBase *adjacent_cell, Wall *w)
 

	
 
#include "far_mem_5.h"
 

	
 
#define SumFluxFromWalls( _vleafcellp_, _flux_function_ ) \
 
(( _vleafcellp_->ReduceCellAndWalls<double>( far_3_arg_mem_fun( *this, &_flux_function_ ) ) ))
 

	
 
#endif
src/forwardeuler.cpp
Show inline comments
 
@@ -11,58 +11,48 @@
 
 *  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.
 

	
 
/* static float maxarg1,maxarg2;
 
   #define FMAX(a,b) (maxarg1=(a),maxarg2=(b),(maxarg1) > (maxarg2) ?	\
 
   (maxarg1) : (maxarg2))
 
   static float minarg1,minarg2;
 
   #define FMIN(a,b) (minarg1=(a),minarg2=(b),(minarg1) < (minarg2) ?	\
 
   (minarg1) : (minarg2))
 
   #define SIGN(a,b) ((b) >= 0.0 ? fabs(a) : -fabs(a))
 
*/
 

	
 

	
 
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. */
 
{
src/infobar.h
Show inline comments
 
@@ -20,42 +20,38 @@
 
 *  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);
 
		//dockwindow->boxLayout()->addWidget(viblab);//,Qt::AlignLeft);
 
		boxLayout()->addStretch();
 
		boxLayout()->addWidget(virtleaf);//, Qt::AlignHCenter);
 
		boxLayout()->addStretch();
 
	
 
		//dockwindow->boxLayout()->addWidget(psblab);//, Qt::AlignRight);
 
	}
 
	
 
	void SetText(QString text) {
 
		virtleaf->setText(QString("<h1>The Virtual Leaf</h1>\n<center><b>Model:</b> <i>%1</i></center>").arg(text));
 
	}
 
	
 
private:
 
	//Q3DockWindow *dockwindow;
 
	QLabel *virtleaf;
 
};
 

	
 
#endif
 
\ No newline at end of file
src/mainbase.cpp
Show inline comments
 
@@ -199,62 +199,51 @@ void MainBase::XMLReadSettings(xmlNode *
 
			
 
			
 
		}
 
		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.);
 
	
 
	//QRectF bb( ll.x - border.x, ll.y - border.y, ur.x-ll.x + 2*border.x, ur.y-ll.y + 2*border.y );
 
	
 
	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,QRectF(),QRectF(-5000,-5000, 10000, 10000));
 
		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);
 
		//pdf.setPageSize(QPrinter::Custom);
 
		QPainter painter(&pdf);
 
		//	cerr << "Cell::Magnification() = " << Cell::Magnification() << endl;
 
		//if (sizex==0 || sizey==0) {
 
			// always fit to page
 
		//	canvas.render(&painter);
 
		//} else {
 
		//	canvas.render(&painter,QRectF(),QRectF(-5000,-5000, 10000, 10000));
 
		//}
 
		canvas.render(&painter, QRectF(), QRectF(-5000,-5000, 10000, 10000));
 
		
 
		cerr << "Rendering to printer\n";
 
	}
 
}
 

	
 
void MainBase::CutSAM() {
 
	
 
	mesh.CutAwaySAM();
 
	
 
}
src/mainbase.h
Show inline comments
 
@@ -37,118 +37,98 @@
 
#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;
 
    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 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 double getFluxArrowsize(void) { return 10.;}
 
    
 
    /* void Save(const char *fname, const char *format, int width=640) {
 
      
 
    //cerr << "Initializing Pixmap\n";
 
      
 
    cerr << "Saving to file " << fname << endl;
 
    QPixmap *image=new QPixmap(width, (int) (((double)canvas.height()/
 
    (double)canvas.width())*((double)width)));
 

	
 
    //QPicture *image = new QPicture();
 
      
 
    //cerr << "Done initializing QPixmap image(640, " << (((double)canvas.height()/(double)canvas.width())*640.) << ")\n";
 
    QPainter im(image);
 
    //cerr << "Done initializing image\n";
 
    im.scale((double)width/canvas.width(),(double)width/canvas.width());
 
    canvas.render(&im, QRectF(0,0,canvas.width(),canvas.height()) );
 
    //im.end();      
 
    image->save(QString(fname), format);
 
    }*/
 
    
 

	
 
    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) {
 
      timeout = 0; // merely to obviate 'warning unused parameter' message
 
      cerr << message.toAscii().constData() << endl;
 
    }
 
    Mesh &mesh;
 
	
 
 protected:
 
    QGraphicsScene &canvas;
 
    virtual xmlNode *XMLSettingsTree(void) 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;
 
    bool hidecellsp;
 
};
 

	
 
//#include <qapplication.h>
 
#define TIMESTEP double MainBase::TimeStep(void)
 
#define INIT void MainBase::Init(char *leaffile)
 

	
 
#endif
src/matrix.cpp
Show inline comments
 
@@ -21,62 +21,58 @@
 

	
 
#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=(double **)malloc(3*sizeof(double *));
 
//  mat[0]=(double *)malloc(9*sizeof(double));
 
  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
 
  //free(mat[0]);
 
  //free(mat);
 
  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];
 
  }
src/mesh.h
Show inline comments
 
@@ -38,172 +38,134 @@
 
#include "cell.h"
 
#include "node.h"
 
#include "simplugin.h"
 
#include <QVector>
 
#include <QPair>
 
#include <QDebug>
 

	
 
using namespace std;
 
// new queue which rejects duplicate elements
 
template<class T, class C = deque<T> > class unique_queue : public queue<T,C> {
 
	
 
public:
 
	typedef typename C::value_type value_type;
 
	// reimplements push: reject element if it exists already
 
	void push(const value_type &x) {
 
		if (find (queue<T,C>::c.begin(),queue<T,C>::c.end(),x)==queue<T,C>::c.end()) {
 
			queue<T,C>::c.push_back(x);
 
		}
 
	}
 
	void clear(void) {
 
		queue<T,C>::c.clear();
 
	}
 
};
 

	
 
//template<class P> P& deref_ptr<P>( P *obj) { return *obj; }
 
template<class P> P& deref_ptr ( P *obj) { return *obj; }
 

	
 

	
 
class Mesh {
 
	
 
	friend class Cell;
 
	friend class Node;
 
	friend class FigureEditor;
 
	
 
public: 
 
	Mesh(void) {
 
		// Make sure the reserved value is large enough if a cell is added
 
		// in "Divide" when the capacity is insufficient, "cells" might be
 
		// relocated including the current Cell (i.e. the value of *this)
 
		// calling "Mesh::IncreaseCapacityIfNecessary" (from another
 
		// object than Cell, e.g. Mesh) before entering Divide will solve
 
		// this issue (solved now).
 
		cells.reserve(2);
 
		nodes.reserve(500);
 
		
 
		//boundary_polygon = new BoundaryPolygon();
 
		
 
		time = 0.;
 
		plugin = 0;
 
	};
 
	~Mesh(void) {
 
		delete boundary_polygon;
 
		/* if (plugin)
 
			delete plugin;*/
 
	};
 
	
 
	void Clean(void);
 
	//void Plane(int xwidth, int ywidth, int nx, int ny, bool randomP=false);
 
	Cell &EllipticCell(double xc, double yc, double ra, double rb, int nnodes=10, double rotation=0);
 
	Cell &CircularCell(double xc, double yc, double r, int nnodes=10) {
 
		return EllipticCell(xc, yc, r, r, nnodes, 0);
 
	}
 
	Cell &LeafPrimordium(int n, double pet_length);
 
	Cell &LeafPrimordium2(int n);
 
	Cell *RectangularCell(const Vector ll, const Vector ur, double rotation = 0);
 
	void CellFiles(const Vector ll, const Vector ur);
 
	
 
	/*  void GMVoutput(ostream &os, 
 
	 const char *codename=0, const char *codever=0,
 
	 const char *comments=0);*/
 
	//void RandPoints(int npoints);
 
	
 
	inline Cell &getCell(int i) {
 
		if ((unsigned)i<cells.size())
 
			return *cells[i];
 
		else {
 
                        #ifdef QDEBUG
 
                        qDebug() << i << endl;
 
                        qDebug() << "size is " << cells.size() << endl;
 
                        #endif
 
			abort();
 
			//	throw("Index out of range in Mesh::getCell");
 
		}
 
	}
 
	
 
	inline Node &getNode(int i) {
 
		//if (i >= nodes.size() || i < 0) {
 
		//  cerr << "Mesh::getNode: Warning. Index " << i << " out of range.\n";
 
		// }
 
		return *nodes[i];    
 
	}
 
	
 
	//double Diffusion(void);
 
	inline int size(void) {
 
		return cells.size();
 
	}
 
	inline int nnodes(void) {
 
		return nodes.size();
 
	}
 
	//void SortNBLists(void);
 
	
 
	/*template<class Op> void LoopCells(Op f) {
 
	 for (vector<Cell>::iterator i=cells.begin();
 
	 i!=cells.end();
 
	 i++) {
 
	 f(*i); 
 
	 }
 
	 }*/
 
	
 
	/*! \brief Calls function f for all Cells f.
 
	 
 
	 Using this template requires some fiddling with function adaptors bind2nd and mem_fun_ref.
 
	 
 
	 Example usage for calling a member function on each cell:
 
	 
 
	 mesh.LoopCells( bind2nd (mem_fun_ref( &Cell::DrawDiffEdges), &canvas ) );
 
	 
 
	 This calls Cell's member function DrawDiffEdges, taking one
 
	 argument canvas, on all Cell objects in the current Mesh.
 
	 
 
	 */
 

	
 
	template<class Op> void LoopCells(Op f) {
 
		for (vector <Cell *>::iterator i=cells.begin();
 
			 i!=cells.end();
 
			 i++) {
 
			f(**i);
 
		}
 
		//for_each(cells.begin(),cells.end(),f);
 
	}
 
	
 
	template<class Op> void LoopWalls(Op f) {
 
		for (list <Wall *>::iterator i=walls.begin();
 
			 i!=walls.end();
 
			 i++) {
 
			f(**i);
 
		}
 
	}
 
	
 
	// if the amount of cells might increase, during looping, use this template
 
	template<class Op> void LoopCurrentCells(Op f) {
 
		vector<Cell *> current_cells = cells;
 
		for (vector <Cell *>::iterator i=current_cells.begin();
 
			 i!=current_cells.end();
 
			 i++) {
 
			f(**i);
 
			
 
		}
 
		//for_each(cells.begin(),cells.end(),f);
 
	}
 
	
 
	template<class Op> void LoopNodes(Op f) {
 
		for (vector<Node *>::iterator i=nodes.begin();
 
			 i!=nodes.end();
 
			 i++) {
 
			f(**i); 
 
		}
 
	}
 
	
 
	template<class Op> void RandomlyLoopNodes(Op f) {
 
		
 
		MyUrand r(shuffled_nodes.size());
 
		random_shuffle(shuffled_nodes.begin(),shuffled_nodes.end(),r);
 
		
 
		for (vector<Node *>::const_iterator i=shuffled_nodes.begin();
 
			 i!=shuffled_nodes.end();
 
			 i++) {
 
			f(*shuffled_nodes[*i]);
 
		}
 
		
 
	}
 
	
 
	template<class Op> void RandomlyLoopCells(Op f) {
 
@@ -235,55 +197,48 @@ public:
 
			f(**i,g,h); 
 
		}
 
	}
 
	
 
	void DoCellHouseKeeping(void) {
 
		vector<Cell *> current_cells = cells;
 
		for (vector<Cell *>::iterator i = current_cells.begin();
 
			 i != current_cells.end();
 
			 i ++) {
 
			plugin->CellHouseKeeping(*i);
 
			
 
			// Call functions of Cell that cannot be called from CellBase, including Division
 
			if ((*i)->flag_for_divide) {
 
				if ((*i)->division_axis) {
 
					(*i)->DivideOverAxis(*(*i)->division_axis);
 
					delete (*i)->division_axis;
 
					(*i)->division_axis = 0;
 
				} else {
 
					(*i)->Divide();
 
				}
 
				(*i)->flag_for_divide=false;
 
			}
 
		}
 
	}
 
/*	template<class Op1, class Cont> void ExtractFromCells(Op1 f, Cont res) {
 
		for (vector<Cell>::iterator i=cells.begin();
 
			 i!=cells.end();
 
			 i++) {
 
			*(res++) = ( f(*i) );
 
		}
 
	}*/
 
	
 
	// Apply "f" to cell i
 
	// i.e. this is an adapter which allows you to call a function
 
	// operating on Cell on its numeric index index
 
	template<class Op> void cell_index_adapter(Op f,int i) {
 
		f(cells[i]);
 
	}
 
	
 
	double DisplaceNodes(void);
 
	
 
	void BoundingBox(Vector &LowerLeft, Vector &UpperRight);
 
	int NEqs(void) {     int nwalls = walls.size();
 
		int ncells =cells.size();
 
		int nchems = Cell::NChem();
 
		
 
		// two eqs per chemical for each walls, and one eq per chemical for each cell
 
		// This is for generality. For a specific model you may optimize
 
		// this by removing superfluous (empty) equations.
 
		int neqs = 2 * nwalls * nchems + ncells * nchems;
 
		
 
		return neqs;
 
	}
 
	void IncreaseCellCapacityIfNecessary(void) {
 
		
 
@@ -314,67 +269,64 @@ public:
 
	}
 
	double Area(void);
 
	double MeanArea(void) {
 
		double sum=0.;
 
		for (vector<Cell *>::const_iterator i=cells.begin();
 
			 i!=cells.end();
 
			 i++) {
 
			sum+=(*i)->Area();
 
		}
 
		return sum/(double)NCells();
 
	}
 
	
 
	void SetBaseArea(void);
 
	int NCells(void) const {
 
		return cells.size();
 
	}
 
	inline int NNodes(void) const {
 
		return nodes.size();
 
	}
 
	void PrintQueue(ostream &os) {
 
		while (!node_insertion_queue.empty()) {
 
			os << node_insertion_queue.front() << endl;
 
			node_insertion_queue.pop();
 
		}
 
		//copy (node_insertion_queue.begin(),node_insertion_queue.end(),ostream_iterator<Edge>(cerr, " "));
 
	}
 
	
 
	void InsertNodes(void) {
 
		// insert the nodes in the insertion queue
 
		while (!node_insertion_queue.empty()) {
 
			
 
			//cerr << node_insertion_queue.front() << endl;
 
			InsertNode(node_insertion_queue.front());
 
			node_insertion_queue.pop();
 
		}
 
		
 
	}
 
	
 
	void Clear(); 
 
	
 
	//  template<class ReactFunction> ReactDiffuse(const double D, ReactFunction& react) {
 
	void ReactDiffuse( double delta_t = 1 );
 
	//void Diffuse(const double D);
 
	double SumChemical(int ch);
 
	void SetChemical(int ch, double value) {
 
		for (vector<Cell *>::iterator c=cells.begin();
 
			 c!=cells.end();
 
			 c++) {
 
			(*c)->chem[ch]=value;
 
		}
 
	}
 
	
 
	// used for interacing with ODE-solvers (e.g. NRCRungeKutta)
 
	void setValues(double x, double *y);
 
	double *getValues(int *neqs);
 
	void Derivatives(double *derivs);
 
#ifdef QTGRAPHICS
 
	inline void DrawBoundary(QGraphicsScene *c) {
 
		boundary_polygon->Draw(c);
 
	}
 
	void DrawNodes(QGraphicsScene *c) const;
 
	
 
#endif
 
	double max_chem;
 
	
 
	void XMLSave(const char *docname, xmlNode *settings=0) const;
 
	void XMLRead(const char *docname, xmlNode **settings=0, bool geometry = true, bool pars = true, bool simtime = true);
 
@@ -406,79 +358,72 @@ public:
 
		return boundary_polygon->Offset();
 
	}
 
	
 
	inline double Factor(void) {
 
		return boundary_polygon->Factor();
 
	}
 
	
 
	void DeleteLooseWalls(void);
 
	void FitLeafToCanvas(double width, double height);
 
	void AddNodeSet(NodeSet *node_set) {
 
		node_sets.push_back(node_set);
 
	}
 
	
 
	void CleanChemicals(const vector<double> &clean_chem);
 
	void CleanTransporters(const vector<double> &clean_transporters);
 
	void RandomizeChemicals(const vector<double> &max_chem, const vector<double> &max_transporters);
 
	inline double getTime(void) const { return time; }
 
	string getTimeHours(void) const; 
 
	inline void setTime(double t) { time = t; }
 
	double CalcProtCellsWalls(int ch) const;  
 
	void SettoInitVals(void);
 
	QVector<qreal> VertexAngles(void);
 
	QVector< QPair<qreal,int> > VertexAnglesValues(void);
 
	void SetSimPlugin(SimPluginInterface *new_plugin) {
 
		/* if (plugin) 
 
			delete plugin;*/
 
		plugin=new_plugin;
 
	}
 
	QString ModelID(void) { return plugin?plugin->ModelID():QString("undefined"); }
 
	void StandardInit(void);	
 

	
 
	Node* findNextBoundaryNode(Node*);
 

	
 
private:
 
	
 
	// Data members
 
	vector<Cell *> cells;
 
	vector<Node *> nodes;
 
	list<Wall *> walls; // we need to erase elements from this container frequently, hence a list.
 
public:
 
	vector<NodeSet *> node_sets;
 
private:
 
	vector<Node *> shuffled_nodes;
 
	vector<Cell *> shuffled_cells;
 
	unique_queue<Edge> node_insertion_queue;
 
	BoundaryPolygon *boundary_polygon;
 
	double time;
 
	SimPluginInterface *plugin;
 
	
 
	// Private member functions
 
	void AddNodeToCell(Cell *c, Node *n, Node *nb1 , Node *nb2);
 
	void AddNodeToCellAtIndex(Cell *c, Node *n, Node *nb1 , Node *nb2, list<Node *>::iterator ins_pos);
 
	void InsertNode(Edge &e);
 
	inline Node *AddNode(Node *n) {
 
		nodes.push_back(n);
 
		shuffled_nodes.push_back(n);
 
		n->m=this;
 
		return n;
 
	}
 
	
 
	inline Cell *AddCell(Cell *c) {
 
		cells.push_back(c);
 
		shuffled_cells.push_back(c);
 
		//cerr << "Shuffled cell indices:  ";
 
		/*copy(shuffled_cells.begin(),shuffled_cells.end(),ostream_iterator<int>(cerr," "));
 
		 cerr << endl;*/
 
		c->m=this;
 
		return c;
 
	}
 
	
 
	//int Delaunay(void);
 
	void CircumCircle(double x1,double y1,double x2,double y2,double x3,double y3,
 
					  double *xc,double *yc,double *r);
 
	
 
	
 
	// void RenumberCells(void);
 
	
 
};
 
#endif
src/modelcatalogue.cpp
Show inline comments
 
@@ -83,51 +83,48 @@ void ModelCatalogue::LoadPlugin(const ch
 
  QDir pluginDir(QApplication::applicationDirPath()); 
 
  QStringList plugin_filters; // filter for plugins, i.e "*.dll", "*.dylib"
 
	
 
	
 
#if defined(Q_OS_WIN) 
 
  if (pluginDir.dirName().toLower() =="debug" 
 
      ||pluginDir.dirName().toLower() =="release") 
 
    pluginDir.cdUp(); 
 
  //plugin_filters << "*.dll";
 
#elif defined(Q_OS_MAC) 
 
  if (pluginDir.dirName() =="MacOS"){ 
 
    pluginDir.cdUp(); 
 
    pluginDir.cdUp(); 
 
    pluginDir.cdUp(); 
 
  } 
 
  //plugin_filters << "*.dylib";
 
#endif
 
  plugin_filters << model;
 
  pluginDir.setNameFilters(plugin_filters);
 
	
 
  if (!pluginDir.cd("models")) {
 
    MyWarning::error("Directory 'models' not found!");
 
  }
 
	
 
	
 
  //QVector<SimPluginInterface *> plugins;
 
	
 
  QStringList modelnames=pluginDir.entryList(QDir::Files);
 
  if (modelnames.empty()) {
 
    MyWarning::error("Model %s not found - hint: do not include path in filename.",model);
 
  }
 
  foreach (QString fileName, modelnames){ 
 
    QPluginLoader loader(pluginDir.absoluteFilePath(fileName)); 
 
		
 
    if (SimPluginInterface *plugin = 
 
	qobject_cast<SimPluginInterface *>(loader.instance())) {
 
      models.append(plugin); 
 
      //MyWarning::warning("Successfully loaded model %s",fileName.toStdString().c_str());
 
    } else {
 
      MyWarning::warning("Could not load plugin %s",fileName.toStdString().c_str());
 
    }
 
  }
 
}
 

	
 
void ModelCatalogue::InstallFirstModel() {
 
	InstallModel(models[0]);
 
}
 
void ModelCatalogue::PopulateModelMenu() {
 
	foreach (SimPluginInterface *model, models) {
 
		QAction *modelaction = new QAction(model->ModelID(), mainwin); 
 
		QVariant data;
 
@@ -139,27 +136,25 @@ void ModelCatalogue::PopulateModelMenu()
 
	connect(mainwin->modelmenu, SIGNAL(triggered(QAction *)), this, SLOT(InstallModel(QAction *)) );
 
}	
 

	
 
void ModelCatalogue::InstallModel(QAction *modelaction) {
 
	QVariant data = modelaction->data();
 
	SimPluginInterface *model = data.value<SimPluginInterface *>();
 
	cerr << "You chose model " << model->ModelID().toStdString() << "!\n";
 
	mesh->Clean();
 
	InstallModel(model);
 
}
 

	
 
void ModelCatalogue::InstallModel(SimPluginInterface *plugin) {
 
	
 
  // make sure both main and plugin use the same static datamembers (ncells, nchems...)
 
  plugin->SetCellsStaticDatamembers(CellBase::GetStaticDataMemberPointer());
 
	
 
  mesh->SetSimPlugin(plugin);
 
  Cell::SetNChem(plugin->NChem());
 
  plugin->SetParameters(&par);
 

	
 
  if (mainwin) {
 
    mainwin->RefreshInfoBar();
 
    mainwin->Init(0);
 
  }
 
  //	mesh->StandardInit();
 
	
 
}
src/node.cpp
Show inline comments
 
@@ -164,50 +164,48 @@ void Node::DrawOwners(QGraphicsScene *c)
 
  
 
  QGraphicsSimpleTextItem *number = new QGraphicsSimpleTextItem ( QString (text.str().c_str()), 0, c );
 
  number->setFont( QFont( "Helvetica", par.nodenumsize, QFont::Bold) );
 
  number->setPen( QPen(par.textcolor) );
 
  number->setZValue(20);
 
  number->show();
 
  Vector offs=Cell::Offset();
 
  
 
  number ->setPos(((offs.x+x)*Cell::Factor()),
 
		  ((offs.y+y)*Cell::Factor()) );
 
}
 

	
 

	
 

	
 
QVector<qreal> Node::NeighbourAngles(void) {
 
	
 
	QVector<qreal> angles;
 
	for (list<Neighbor>::iterator i=owners.begin();
 
		 i!=owners.end();
 
		 i++) {
 
		
 
		Vector v1 = (*this - *i->nb1).Normalised();
 
		Vector v2 = (*this - *i->nb2).Normalised();	
 
	
 
		//angles.push_back(atan2(v2.y,v2.x)-atan2(v1.y,v1.x));
 
		//angles.push_back(atan2(v2.y,v2.x)-atan2(v1.y,v1.x));
 
		double angle = v1.SignedAngle(v2);
 
		if (angle<0) {
 
			//cerr << "Changing sign of angle " << angle << endl;
 
			angle = angle + 2*Pi;
 
		}
 
		angles.push_back(angle);
 
		
 
		//cerr << "Cell " << i->cell->Index() << ": " <<  v1 << " and " << v2 << ": angle = " << angles.back() << ", " << v1.Angle(v2) << endl;
 
		
 
	}
 
	
 
	double sum=0.;
 
	for (QVector<qreal>::iterator i=angles.begin();
 
		 i!=angles.end();
 
		 i++) {
 
		sum+=*i;
 
	}
 
	//cerr << "Angle sum = " << sum << endl;
 
	// Check if the summed angle is different from 2 Pi 
 
	if (fabs(sum-(2*Pi))>0.0001) {
 
		
 
		MyWarning::warning("sum = %f",sum);
 
	}
 
		return angles;
src/node.h
Show inline comments
 
@@ -104,122 +104,101 @@ public:
 
  Node(double x,double y, double z=0);
 

	
 
  Node(const Node &src);
 

	
 
  explicit Node(const Vector &src); // "nonconverting" - explicit constructor syntax required
 

	
 
  virtual ~Node() {}
 

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

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

	
 
  inline bool BoundaryP(void) const { return boundary; }
 

	
 
  inline void SetBoundary(void) { boundary = true; }
 

	
 
  inline void UnsetBoundary(void) { boundary = false; }
 

	
 
  inline void SetSAM(void) { sam = true; }
 

	
 
  inline void toggleBoundary(void) {
 
    boundary = !boundary;
 
  }
 
  
 
  //void Displace(void);
 

	
 
  Cell &getCell(const Neighbor &i);
 
  
 
  //Node &getNode(int i);
 
  ostream &print(ostream &os) const;
 
  void XMLAdd(xmlNodePtr nodes_node) const;
 
  
 
#ifdef QTGRAPHICS
 
  void Draw(QGraphicsScene &c, QColor color=QColor("black"), int size = 10) const;
 
  void DrawIndex(QGraphicsScene *c) const;
 
  void DrawOwners(QGraphicsScene *c) const;
 
#endif
 
  
 
  // temporary function for easier debugging
 
  inline int CellsSize(void) const {
 
    return owners.size();
 
  }
 

	
 
  inline int Value(void) const {
 
    return owners.size();
 
  }
 

	
 
  void Fix(void) {
 
    fixed=true;
 
  }
 
  inline bool Fixed(void) const {
 
    return fixed;
 
  }
 
  inline void Unfix(void) {
 
    fixed=false;
 
  }
 
  inline void MarkDead(void) {
 
    dead=true;
 
  }
 
  inline bool DeadP(void) {
 
    return dead;
 
  }
 

	
 
  /*void UpdateAfterNodeRemoved(int n) {
 
    for (list<Neighbor>::iterator i=owners.begin();
 
    i!=owners.end();
 
    i++) {
 
    if (i->nb1>=n) i->nb1--;
 
    if (i->nb2>=n) i->nb2--;
 
    }
 
    }
 
 
 
    void UpdateAfterCellRemoved(int n) {
 
    for (list<Neighbor>::iterator i=owners.begin();
 
    i!=owners.end();
 
    i++) {
 
    if (i->cell>=n) i->cell--;
 
    }
 
    }
 
  */
 
  
 
  inline void Mark(void) {
 
    marked=true;
 
  }
 
  inline void Unmark(void) {
 
    marked=false;
 
  }
 
  inline bool Marked(void) const {
 
    return marked;
 
  }
 
  
 
  inline void setPos( Vector p ) { 
 
    x = p.x;
 
    y = p.y;
 
    z = p.z;
 
  }
 
  inline bool SamP(void) const { return sam; }
 
  //enum boundary_type {NoBoundary, Noflux, SourceSink, SAM};
 

	
 
  //!\brief Calculate angles with neighboring vertices
 
  //! Sum of angles should be 2*Pi
 
  QVector<qreal> NeighbourAngles(void);
 
private:
 
  
 
  // "owners" lists the cells to which this cell belong
 
  // and the two neighboring nodes relative to each cell
 
  list< Neighbor > owners;
 
  
 
  Mesh *m;
 
  int index;
 
  static int nnodes;
 
  static double target_length;
 
  
 
  // if the node belongs to a NodeSet, node_set contains the pointer. Otherwise it is 0.
 
  NodeSet *node_set; 
 
  // fixed nodes cannot move. E.g. to represent the petiole
 
  bool fixed;
 
  bool boundary; // true if node is at the edge of the leaf
 
  bool sam; // true if node is connected to the shoot
 
  bool dead;
 
  bool marked;
 
};
src/nodeitem.cpp
Show inline comments
 
@@ -33,71 +33,52 @@ static const std::string _module_id("$Id
 
extern Parameter par;
 

	
 
NodeItem::NodeItem( Node *n, QGraphicsScene *canvas )
 
  : QGraphicsItem( 0, canvas ), SimItemBase( n, canvas) {
 
  
 
  brush = Qt::darkGray;
 
  
 
  const double mag = par.node_mag;
 
  ellipsesize=QRectF(-1*mag, -1*mag, 2*mag, 2*mag);
 

	
 
}
 

	
 
void NodeItem::userMove(double dx, double dy) {
 
  QGraphicsItem::moveBy( dx, dy );
 
  
 
  class_cast<Node *>(obj)->x += (dx/Cell::Magnification());
 
  class_cast<Node *>(obj)->y += (dy/Cell::Magnification());
 
}
 

	
 

	
 

	
 
void NodeItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *)
 
{
 

	
 
  // from Qt4.2 example: "elastic nodes"
 
  //painter->setPen(Qt::NoPen);
 
  //painter->setBrush(Qt::darkGray);
 
  //painter->drawEllipse(-70, -70, 200, 200);
 
  
 
  /* QRadialGradient gradient(-30, -30, 100);
 
     
 
  if (option->state & QStyle::State_Sunken) {
 
  gradient.setCenter(30, 30);
 
  gradient.setFocalPoint(30, 30);
 
  gradient.setColorAt(1, QColor(Qt::yellow).light(120));
 
  gradient.setColorAt(0, QColor(Qt::darkYellow).light(120));
 
  } else {
 
  gradient.setColorAt(0, Qt::yellow);
 
  gradient.setColorAt(1, Qt::darkYellow);
 
  }
 
  
 
  painter->setBrush(gradient); */
 
  option = NULL; // use assignment merely to obviate compilation warning
 
  
 
  painter->setBrush(brush);
 
  painter->setPen(Qt::NoPen);
 
  // const static double mag=20.;
 
  painter->drawEllipse(ellipsesize);
 
}
 

	
 

	
 
QPainterPath NodeItem::shape() const
 
{
 
    QPainterPath path;
 
    path.addEllipse(ellipsesize);
 
    return path;
 
}
 

	
 
QRectF NodeItem::boundingRect() const
 
{
 
  qreal penwidth = 0;// painter->pen()->widthF();
 
  return QRectF(ellipsesize.x()-penwidth/2.,ellipsesize.y()-penwidth/2.,
 
		ellipsesize.width()+penwidth, ellipsesize.height()+penwidth);
 
}
 

	
 
// polymorphic OnClick functions
 
void NodeItem::OnClick(void) {
 
  Node *n = &getNode();
 
  n->toggleBoundary();
 
  setColor();
 
  update();
src/nodeset.h
Show inline comments
 
@@ -10,69 +10,63 @@
 
 *  (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.
 
 *
 
 */
 

	
 

	
 
#ifndef _NODESET_H_
 
#define _NODESET_H_
 

	
 
#include <algorithm>
 
#include <numeric>
 
#include <list>
 
#include <iterator>
 
#include "node.h"
 

	
 
//class xmlNode;
 

	
 
class NodeSet : public list<Node *> {
 
  
 
 public:
 
  NodeSet(void) {
 
    done = false;
 
  }
 
  
 
  inline bool DoneP(void) { return done; }
 
  inline void ResetDone(void) { done = false; }
 
  
 
  void AddNode(Node * n) {
 
    push_back(n);
 
    n->node_set = this;
 
  }
 

	
 
  //  list <Node *? getNodes(void) {
 
  //  return set;
 
  //}
 

	
 
  list <Cell *> getCells(void) {
 
    
 
    list<Cell *> cellset;
 
    
 
    for (list<Node *>::const_iterator i=begin();
 
	 i!=end();
 
	 i++) {
 
      transform ( (*i)->owners.begin(), (*i)->owners.end(), back_inserter( cellset ) , mem_fun_ref ( &Neighbor::getCell ));
 
    }
 
    
 
    cellset.sort();
 
    
 
    // remove all non-unique elements
 
    // (unique moves all unique elements to the front and returns an iterator to the end of the unique elements;
 
    // so we simply erase all remaining elements.
 
    cellset.erase(::unique(cellset.begin(), cellset.end() ), 
 
		  cellset.end() );
 
    
 
    // remove boundary_polygon
 
    cellset.erase( find_if ( cellset.begin(), cellset.end(), mem_fun( &Cell::BoundaryPolP  ) ) );
 
    return cellset;
 
  }
 

	
 
  void CleanUp(void) {
 
@@ -135,40 +129,38 @@ class NodeSet : public list<Node *> {
 
	  
 
	  list<int> new_areas;
 
	  
 
	 // cerr << "Nodeset says: dh = " << dh << " ...";
 
	  if (dh < -sum_stiff || RANDOM()<exp((-dh - sum_stiff)/par.T) ) {
 
		
 
		// ACCEPT
 
		// recalculate areas of cells
 
		for_each ( celllist.begin(), celllist.end(), mem_fun ( &Cell::RecalcArea ) );
 
		
 
		// recalculate integrals of cells
 
		for_each ( celllist.begin(), celllist.end(), mem_fun ( &Cell::SetIntegrals ) );
 
      
 
		
 
    } else {
 
      // REJECT
 
      
 
      // Move the set's nodes back to their original position
 
      for ( list<Node *>::iterator n = begin();
 
	    n!= end();
 
	    ++n ) {
 
	
 
	(*n)->x-=rx;
 
	(*n)->y-=ry;
 
	// (*n)->z -= rz;
 
	  }
 
      
 
      
 
    }
 
  }
 
  
 
  void XMLAdd(xmlNode *root) const;
 
  void XMLRead(xmlNode *root, Mesh *m);
 
 private:
 
  // list<Node *> set;
 
  bool done;
 
};
 

	
 
ostream &operator<<(ostream &os, const NodeSet &ns);
 
#endif
src/output.cpp
Show inline comments
 
@@ -3,49 +3,48 @@
 
 *  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.
 
 *
 
 */
 
 
#include <string>
 
#include <stdio.h>
 
#include <string.h>
 
#include <stdlib.h>
 
#include <errno.h>
 
//#include <unistd.h>
 
#include <sys/types.h>
 
#include <sys/stat.h>
 
#include "warning.h"
 
#include "parameter.h"
 
#include "output.h"
 
 
 
#include <QDir>
 
#include <QFileInfo>
 
 
static const std::string _module_id("$Id$");
 
 
using namespace MyWarning;
 
 
#define FNAMESIZE 100
 
 
int OpenFileAndCheckExistance(FILE **fp,const char *fname,char *ftype) {
 
  
 
  *fp=fopen(fname,ftype);
 
  if (*fp==NULL) 
 
    return FALSE;
 
  
 
  if (!strncmp(ftype,"a",1)) {
 
    if (ftell(*fp)>0L) return TRUE;
 
@@ -64,163 +63,89 @@ int FileExistsP(const char *fname) {
 
  return TRUE;
 
 
}
 
		       
 
int YesNoP(const char *message) {
 
  
 
  char answer[100];
 
 
  fprintf(stderr,"%s (y/n) ",message);
 
  fflush(stderr);
 
  
 
  scanf("%s",answer);
 
  while (strcmp(answer,"y") && strcmp(answer,"n")) {
 
    fprintf(stderr,"\n\bPlease answer 'y' or 'n'. ");
 
    fflush(stderr);
 
    scanf("%s",answer);
 
  }
 
  
 
  if (!strcmp(answer,"y")) return TRUE;
 
  
 
  return FALSE;
 
    
 
}
 
 
/* //FILE *OpenWriteFile(char *filename) 
 
// {
 
//   FILE *fp;
 
//   fprintf(stderr,"Opening %s for writing\n",filename);
 
	
 
//   if((OpenFileAndCheckExistance(&fp,filename,"r"))==TRUE) {
 
// 	if (!YesNoP("File exists, overwrite?")) {
 
// 	  fprintf(stderr," Could not open file %s for writing, exiting... \n"
 
// 			  ,filename);
 
// 	  exit(0);
 
// 	}
 
//   }
 
  
 
//   if (fp!=NULL) // file existed, but user wants to overwrite
 
// 	fclose(fp);
 
  
 
//   if ((fp=fopen(filename,"w"))==NULL) {
 
// 	fprintf(stderr," Could not open file %s for writing, exiting... \n"
 
// 			,filename);
 
// 	exit(0);
 
//   }
 
	
 
//   return fp;
 
// }
 
*/
 
 
FILE *OpenWriteFile(const char *filename) 
 
{
 
 
  char fname[FNAMESIZE];
 
 
  FILE *fp;
 
 
  fprintf(stderr,"Opening %s for writing\n",filename);
 
	
 
  if(FileExistsP(filename)==TRUE) {
 
  
 
    if (false/*par.interactive*/) {
 
      char *message=(char *)malloc(2000*sizeof(char));
 
      if (!YesNoP("File exists, overwrite?")) {
 
	sprintf(message," Could not open file %s for writing, exiting... \n"
 
		,filename);
 
	//exit(0);
 
	throw(message);
 
      }
 
    } else {
 
      /* Rename old file */
 
      sprintf(fname, "%s~",filename);
 
      rename(filename, fname);
 
      
 
    }
 
  }
 
  
 
  strncpy(fname, filename, FNAMESIZE-1);
 
  
 
  if ((fp=fopen(fname,"w"))==NULL) {
 
    char *message=(char *)malloc(2000*sizeof(char));
 
    sprintf(message," Could not open file %s for writing: "
 
	    ,fname);
 
    perror("");
 
    throw(message);
 
  }
 
	
 
  return fp;
 
}
 
 
/*FILE *OpenGZippedWriteFile(const char *filename) 
 
{
 
 
  // Open file that is zipped while it is written
 
  // uses a pipe
 
    
 
  char fname[FNAMESIZE];
 
  char gzname[FNAMESIZE];
 
 
  FILE *fp;
 
  extern Parameter par;
 
 
  // step 1, add ".gz" to the filename
 
  sprintf(gzname, "%s.gz", filename);
 
  
 
  // and check whether it already exists
 
  fprintf(stderr,"Opening %s for writing\n",gzname);
 
	
 
  if(FileExistsP(gzname)==TRUE) {
 
  
 
    if (par.interactive) {
 
      if (!YesNoP("File exists, overwrite?")) {
 
	fprintf(stderr," Could not open file %s for writing, exiting... \n"
 
		,gzname);
 
	exit(0);
 
      }
 
    } else {
 
      // Rename old file 
 
      snprintf(fname, FNAMESIZE-1, "%s~",gzname);
 
      rename(gzname, fname);
 
      
 
    }
 
  }
 
  
 
  //  strncpy(fname, gzname, FNAMESIZE-1);
 
  char *command=new char[20+sizeof(gzname)];
 
  sprintf(command, "gzip -c > %s", gzname);
 
  
 
  if ((fp=popen(command,"w"))==NULL) {
 
    fprintf(stderr," Could not open file %s for writing: "
 
	    ,fname);
 
    perror("");
 
    exit(-1);
 
  }
 
	
 
  delete[] command;
 
  return fp;
 
}
 
*/
 
 
FILE *OpenReadFile(const char *filename) 
 
{
 
  FILE *fp;
 
 
  fprintf(stderr,"Opening %s for reading\n",filename);
 
  
 
  if((OpenFileAndCheckExistance(&fp,filename,"r"))==FALSE) {	
 
    char *message=(char *)malloc(2000*sizeof(char));
 
    sprintf(message," File %s not found or empty, exiting... \n" ,filename);
 
    throw(message);
 
  }
 
  return fp;
 
}
 
 
 
char *ReadLine(FILE *fp) 
 
{
 
  /* does almost the same as fgetln(), but DEC Unix doesn't understand
 
	 fgetln(). Also I want my function to return a real C string,
 
	 terminated by a \0. */
 
 
  /* The function reads a line from file *fp, and returns a pointer to the
 
	 line read, which can be freed with a normal free(). The length of the
 
@@ -310,59 +235,58 @@ char *Chext(char *filename) {
 
  char *result;
 
 
  for (i=strlen(filename)-1;i>=0;i--) {
 
    if (filename[i]=='.') 
 
      break;
 
    
 
  }
 
  
 
  /* No . found */
 
  if (i==0) {
 
    
 
    result=strdup(filename);
 
  } else {
 
   
 
    /* . found */
 
    result=(char *)malloc((i+1)*sizeof(char));
 
    strncpy(result, filename, i);
 
  }
 
  return result;
 
  
 
  
 
}
 
 
void MakeDir(const char *dirname) {
 
  
 
  cerr << "Entering MakeDir for name " << dirname << "\n";
 
 
#ifdef QTGRAPHICS
 
  QFileInfo file_info(dirname);
 
  
 
  //check for existance
 
  if (file_info.exists()) {
 
    
 
    if (file_info.isDir()) {
 
      // OK 
 
      cerr << "Using existing directory " << dirname << " for data storage.\n";
 
      cerr << "Using existing directory " << dirname << " for data storage." << endl;
 
      return;
 
    } else {
 
      char *message = new char[MESS_BUF_SIZE+1];
 
      snprintf(message, MESS_BUF_SIZE, "%s is not a directory", dirname);
 
      cerr << message << endl;
 
      throw(message);
 
    }
 
    
 
  }
 
 
  // make directory
 
  QDir dir;
 
  if (!dir.mkdir(QString(dirname))) {
 
    char *message = new char[MESS_BUF_SIZE+1];
 
    snprintf(message,MESS_BUF_SIZE,"%s: Error in making directory %s",strerror(errno),dirname);
 
    warning(message);
 
    //strerror(message);
 
    //exit(1);
 
    return;
 
  }
 
  
 
  // check
 
  
 
 
@@ -394,70 +318,24 @@ void MakeDir(const char *dirname) {
 
	} else {
 
	  fprintf(stderr,"Using existing directory %s for data storage.\n",dirname);
 
	}
 
      } else {
 
	snprintf(message, MESS_BUF_SIZE, "%s is not a directory", dirname);
 
	perror(message);
 
	exit(1);
 
      }
 
    } else {
 
      // a different error occurred. Print error and quit 
 
      
 
      snprintf(message,MESS_BUF_SIZE,"Error in making directory %s",dirname);
 
      perror(message);
 
      exit(1);
 
      
 
    }
 
  
 
 
 
  }
 
 
#endif
 
}
 
 
/*bool CanWeWriteP(char *filename) {
 
 
  // check for the existance of file "filename"
 
   // if it exists, ask the user whether we may overwrite it
 
   //false: do not overwrite. true: do overwrite 
 
   
 
  
 
  char message[MESS_BUF_SIZE];
 
  char fname[FNAMESIZE];
 
 
  extern const Parameter par;
 
 
  int status;
 
  status=access(filename, F_OK);
 
  if (status < 0) {// file does not exist, or something else is wrong      
 
    // check error code
 
    if (errno!=ENOENT) {
 
	
 
      // another error occured 
 
      snprintf(message, MESS_BUF_SIZE, "Error checking for existance of %s",filename);
 
      perror(message);	      
 
      exit(1);
 
    }
 
      
 
  } else {
 
      
 
    // file exists, ask for permission to overwrite if interactive
 
    if (par.interactive) {
 
      snprintf(message, MESS_BUF_SIZE, "File %s exists. Overwrite? ",filename);
 
      if (!YesNoP(message))
 
	return false;
 
      else 
 
	return true;
 
    } else {
 
      // Rename old file 
 
      snprintf(fname, FNAMESIZE-1, "%s~",filename);
 
      rename(filename, fname);
 
    }
 
    
 
    return true;
 
  }
 
    
 
  // file does not exist, or user permits overwriting
 
  return true;
 
    
 
}*/
src/output.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
 
 *  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.
 
 *
 
 */
 
 
 
#ifndef _OUTPUT_H_
 
#define _OUTPUT_H_
 
 
#ifdef __cplusplus
 
extern "C" {
 
#endif
 
 
int OpenFileAndCheckExistance(FILE **fp,const char *fname,char *ftype);
 
int YesNoP(const char *message);
 
FILE *OpenWriteFile(const char *filename);
 
FILE *OpenGZippedWriteFile(const char *filename);
 
FILE *OpenReadFile(const char *filename);
 
char *ReadLine(FILE *fp);
 
void CheckFile(FILE *fp);
 
int FileExistsP(const char *fname);
 
char *Chext(char *filename);
 
void MakeDir(const char *dirname);
 
bool CanWeWriteP(char *filename);
 
 
#ifdef __cplusplus
 
}
 
#endif
 
 
 
#define MESS_BUF_SIZE 160
 
#ifndef FALSE
 
#define FALSE 0
 
#define TRUE 1
 
#endif
 
 
#endif
 
/*
 
 *
 
 *  $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.
 
 *
 
 */
 

	
 

	
 
#ifndef _OUTPUT_H_
 
#define _OUTPUT_H_
 

	
 
#ifdef __cplusplus
 
extern "C" {
 
#endif
 

	
 
int OpenFileAndCheckExistance(FILE **fp,const char *fname,char *ftype);
 
int YesNoP(const char *message);
 
FILE *OpenWriteFile(const char *filename);
 
FILE *OpenGZippedWriteFile(const char *filename);
 
FILE *OpenReadFile(const char *filename);
 
char *ReadLine(FILE *fp);
 
void CheckFile(FILE *fp);
 
int FileExistsP(const char *fname);
 
char *Chext(char *filename);
 
void MakeDir(const char *dirname);
 
bool CanWeWriteP(char *filename);
 

	
 
#ifdef __cplusplus
 
}
 
#endif
 

	
 

	
 
#define MESS_BUF_SIZE 160
 
#ifndef FALSE
 
#define FALSE 0
 
#define TRUE 1
 
#endif
 

	
 
#endif
src/parse.cpp
Show inline comments
 
@@ -50,83 +50,79 @@ char *ParsePar(FILE *fp, char *parameter
 
  if (token==NULL) {
 
	error("Parse error: no '=' sign found next to token %s, in line: \n %s.",
 
		  parameter,line);
 
   }
 
 
  // warning("Reading value for token %s...",token);
 
  fprintf(stderr, "[%s = ",token);
 
  
 
  token=strtok(NULL,"=");
 
  if (token==NULL)
 
	error("\nParse error: no value found after '=' sign, in line: \n %s",
 
		  line);
 
 
  value=strdup(token);
 
  free(line);
 
  
 
  return value;
 
      
 
}
 
 
 
int igetpar(FILE *fp,char *parameter, bool wrapflag) {
 
  
 
  // overloaded compatibility function. Doesn't need default parameter
 
  // default = 0
 
  
 
 
  return igetpar(fp, parameter, 0, wrapflag);
 
}
 
 
int igetpar(FILE *fp,char *parameter, int default_val, bool wrapflag) 
 
{
 
  char *token;
 
  int value;
 
  
 
  /* Get token representing the value */
 
  token=ParsePar(fp,parameter, wrapflag);
 
 
  if (token==0) {
 
    /* default value */
 
    warning("No token %s found. Using default value %d.\n", parameter, default_val);
 
    return default_val;
 
  }
 
  /* read it */
 
  sscanf(token,"%d",&value);
 
  fprintf(stderr, "%d]\n",value);
 
  
 
  free(token);
 
 
  return value;
 
  
 
}
 
 
float fgetpar(FILE *fp,char *parameter, bool wrapflag) {
 
   
 
  // overloaded compatibility function. Doesn't need default parameter
 
  // default = 0
 
  
 
  return fgetpar(fp, parameter, 0., wrapflag);
 
 
}
 
 
float fgetpar(FILE *fp, char *parameter, double default_val, bool wrapflag) 
 
{
 
  char *token;
 
  float value;
 
 
  /* Get token representing the value */
 
  token=ParsePar(fp,parameter, wrapflag);
 
 
  if (token==0) {
 
    /* default value */
 
    warning("No token %s found. Using default value %f.\n", parameter, default_val);
 
    return default_val;
 
  }
 
 
  /* read it */
 
  sscanf(token,"%e",&value);
 
 
  fprintf(stderr,"%e]\n",value);
 
  
 
  free(token);
 
 
  return value;
 
@@ -275,50 +271,48 @@ bool bgetpar(FILE *fp, char *parameter, 
 
    if (!strcmp(&token[pos],"no") || !strcmp(&token[pos],"false") || !strcmp(&token[pos],"0"))
 
      value=0;
 
  else
 
    error("Keyword '%s' not recognized. Try yes/no or true/false.\n",&token[pos]);
 
 
  fprintf(stderr, "%s]\n",bool_str(value));
 
 
  return value;
 
 
}
 
 
 
char *SearchToken(FILE *fp, char *token,bool wrapflag) 
 
{
 
  /* This function returns the next line of FILE *fp that contains
 
     the string stored in the null terminated string token */
 
 
  /* remember to free the memory allocated for line */
 
  
 
  unsigned int len;
 
  char *line;
 
  int wrapped=false;
 
  long initial_position;
 
  
 
  /*  rewind(fp); */
 
 
  char *tokenplusspace = (char *)malloc( (strlen(token)+3)*sizeof(char));
 
  strcpy(tokenplusspace, token);
 
  strcat(tokenplusspace," ");
 
  
 
  initial_position=ftell(fp);
 
  if (ferror(fp)) /* error occured */
 
    {
 
      error("%s",strerror(errno));
 
    }
 
 
 
 
  if (feof(fp)) {
 
    warning("End of file\n");
 
  }
 
  
 
  
 
  while (!(wrapped && ftell(fp)>=initial_position)) {
 
 
    /* As long as the search was not wrapped and we are not
 
     * back to where we were, continue searching */
 
		
 
    /* Read a line, and check whether an EOF was found */
 
    if ((line=ReadLine(fp))==NULL) {
 
      /* Yes? wrapflag on? => Wrap. */
src/parse.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
 
 *  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.
 
 *
 
 */
 
 
 
#ifndef _PARSE_H_
 
#define _PARSE_H_
 
 
char *ParsePar(FILE *fp, char *parameter, bool wrapflag);
 
int igetpar(FILE *fp,char *parameter, bool wrapflag);
 
int igetpar(FILE *fp,char *parameter, int default_val, bool wrapflag);
 
float fgetpar(FILE *fp,char *parameter, bool wrapflag);
 
float fgetpar(FILE *fp,char *parameter, double default_val, bool wrapflag);
 
 
/* Get a list of n comma separated doubles */
 
double *dgetparlist(FILE *fp,char *parameter, int n, bool wrapflag);
 
char *sgetpar(FILE *fp,char *parameter, bool wrapflag);
 
char *sgetpar(FILE *fp,char *parameter,const char *default_val, bool wrapflag);
 
bool bgetpar(FILE *fp, char *parameter, bool wrapflag);
 
bool bgetpar(FILE *fp, char *parameter, int default_val, bool wrapflag);
 
char *SearchToken(FILE *fp, char *token, bool wrapflag);
 
int TokenInLineP(char *line,char *token);
 
void SkipToken(FILE *fp,char *token, bool wrapflag);
 
void SkipLine(FILE *fp);
 
char *bool_str(bool bool_var);
 
 
#endif
 
/*
 
 *
 
 *  $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.
 
 *
 
 */
 

	
 

	
 
#ifndef _PARSE_H_
 
#define _PARSE_H_
 

	
 
char *ParsePar(FILE *fp, char *parameter, bool wrapflag);
 
int igetpar(FILE *fp,char *parameter, bool wrapflag);
 
int igetpar(FILE *fp,char *parameter, int default_val, bool wrapflag);
 
float fgetpar(FILE *fp,char *parameter, bool wrapflag);
 
float fgetpar(FILE *fp,char *parameter, double default_val, bool wrapflag);
 

	
 
/* Get a list of n comma separated doubles */
 
double *dgetparlist(FILE *fp,char *parameter, int n, bool wrapflag);
 
char *sgetpar(FILE *fp,char *parameter, bool wrapflag);
 
char *sgetpar(FILE *fp,char *parameter,const char *default_val, bool wrapflag);
 
bool bgetpar(FILE *fp, char *parameter, bool wrapflag);
 
bool bgetpar(FILE *fp, char *parameter, int default_val, bool wrapflag);
 
char *SearchToken(FILE *fp, char *token, bool wrapflag);
 
int TokenInLineP(char *line,char *token);
 
void SkipToken(FILE *fp,char *token, bool wrapflag);
 
void SkipLine(FILE *fp);
 
char *bool_str(bool bool_var);
 

	
 
#endif
src/random.cpp
Show inline comments
 
@@ -120,45 +120,30 @@ void AskSeed(void)
 
  scanf("%d",&seed);
 
  printf("\n");
 
  Seed(seed);
 
}
 
 
int RandomCounter(void) {
 
  return counter;
 
}
 
 
/*! Make a random seed based on the local time
 
\param void
 
\return void
 
**/
 
 
int Randomize(void) {
 
  
 
  // Set the seed according to the local time
 
  struct timeb t;
 
  int seed;
 
 
  ftime(&t);
 
  
 
  seed=abs((int)((t.time*t.millitm)%655337));
 
  Seed(seed);
 
  fprintf(stderr,"Random seed is %d\n",seed);
 
#ifdef QDEBUG
 
  qdebug() << "Random seed is " << seed << endl;
 
#endif
 
  return seed;
 
}
 
 
/** TESTING random generator 
 
#include <vector>
 
#include <fstream>
 
int main(void) {
 
  
 
  MyUrand r(-1);
 
  
 
  vector<int> bucket(100);
 
  for (int i = 0; i<1000000 ; i++) {
 
    bucket[r(100)]++;
 
  }
 
  ofstream out("randomtest.dat");
 
  for (int i = 0; i<=100; i++) {
 
    out << i << " " << bucket[i] << endl;
 
  }
 
}
 
***/
src/random.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
 
 *  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.
 
 *
 
 */
 
 
 
#ifndef _RANDOM_H_
 
#define _RANDOM_H_
 
 
#define MBIG 1000000000
 
#define MSEED 161803398
 
#define MZ 0
 
#define FAC (1.0/MBIG)
 
 
double RANDOM();
 
int Seed(int seed);
 
long RandomNumber(long max);
 
void AskSeed();
 
int Randomize(void);
 
int RandomCounter(void);
 
 
 
 
// Class MyUrand, so we can pass the random generator to STL's random_shuffle,
 
// and get identical simulations for a given random seed.
 
class MyUrand {
 
 
 
  long n;
 
 public:
 
  MyUrand(long nn) {
 
    n=nn;
 
  }
 
  MyUrand(void){};
 
 
 
  void seed(long s) {
 
    Seed(s);
 
  }
 
  
 
  long operator()(long nn) { return RandomNumber(nn)-1; }
 
  long operator()(void) { return RandomNumber(n); }
 
};
 
 
 
 
 
 
 
#endif
 
/*
 
 *
 
 *  $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.
 
 *
 
 */
 

	
 

	
 
#ifndef _RANDOM_H_
 
#define _RANDOM_H_
 

	
 
#define MBIG 1000000000
 
#define MSEED 161803398
 
#define MZ 0
 
#define FAC (1.0/MBIG)
 

	
 
double RANDOM();
 
int Seed(int seed);
 
long RandomNumber(long max);
 
void AskSeed();
 
int Randomize(void);
 
int RandomCounter(void);
 

	
 

	
 

	
 
// Class MyUrand, so we can pass the random generator to STL's random_shuffle,
 
// and get identical simulations for a given random seed.
 
class MyUrand {
 
 
 
  long n;
 
 public:
 
  MyUrand(long nn) {
 
    n=nn;
 
  }
 
  MyUrand(void){};
 
 
 
  void seed(long s) {
 
    Seed(s);
 
  }
 
  
 
  long operator()(long nn) { return RandomNumber(nn)-1; }
 
  long operator()(void) { return RandomNumber(n); }
 
};
 

	
 

	
 

	
 

	
 

	
 

	
 
#endif
src/sqr.h
Show inline comments
 
@@ -5,55 +5,48 @@
 
 *  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/>.
 
 *
 
 *  From "Numerical recipes in C"
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#ifndef _SQR_H_
 
#define _SQR_H_
 

	
 
/* static float sqrarg;
 
#define SQR(a) ((sqrarg=(a)) == 0.0 ? 0.0 : sqrarg*sqrarg)
 

	
 
static double dsqrarg;
 
#define DSQR(a) ((dsqrarg=(a)) == 0.0 ? 0.0 : dsqrarg*dsqrarg)
 
*/
 

	
 

	
 
// redefine these macros as inline functions, to prevent scary
 
// behavior.  (According to compiler warnings, the above macros from
 
// Numerical Recipes in C are officially undefined...)
 
//
 
// However, they seem to work, but it seems safer to redefine them.
 
// Inline functions will behave like macros anyhow.
 
inline double DSQR( double a ) {
 
  
 
  if (a == 0.0) {
 
    return 0.0;
 
  } else {
 
    return a*a;
 
  }
 

	
 
}
 

	
 
inline float SQR( float a ) {
 
   if (a == 0.0) {
 
    return 0.0;
 
  } else {
 
    return a*a;
 
  }
 
}
src/vector.h
Show inline comments
 
@@ -97,49 +97,48 @@ public:
 
    result.z=z-v.z;
 
    
 
    return result;
 
    
 
  }
 
  Vector &operator-=(const Vector &v);
 
  
 
  inline Vector &operator+=(const Vector &v) {
 
  
 
    x+=v.x;
 
    y+=v.y;
 
    z+=v.z;
 
    
 
    return *this;
 
    
 
  }
 
  
 
  Vector operator/(const double divisor) const; // division by a double
 
  Vector operator*(const double multiplier) const; // multiply by a scalar (double)
 
  Vector &operator/=(const double divisor);
 
  Vector &operator*=(const double multiplier);
 
  Vector operator*(const Vector &v) const; // cross product
 
  bool operator==(const Vector &v) const; // comparison
 
  bool operator< (const Vector &v) const; // order x,y,z
 
  //double Norm(void) const; // gives the "norm" (| v |) of v
 
  inline double Norm(void) const {
 
  
 
    return sqrt(DSQR(x)+DSQR(y)+DSQR(z));
 
    
 
  }
 

	
 
  // Quick and dirty Norm (i.e. Manhattan distance)
 
  // (e.g. useful if we want to see if the vec is (0,0,0);
 
  inline double ManhattanNorm(void) const {
 
    return x+y+z;
 
  }
 
  
 
  double SqrNorm(void) const; // gives the square of |v|
 
  void Normalise(void); // normalise myself
 
  Vector Normalised(void) const; // return me normalised
 
  double Angle(const Vector &angle) const; // gives the angle between me and another vector
 
  double SignedAngle(const Vector &v) const;
 
  bool SameDirP(const Vector &v);
 
  double Max(void); // Find max, resp. min value of vector
 
  double Min(void);
 
  Vector Perp2D(void) const {
 
    return Vector(y,-x,0);
 
  }
 
  // data members
src/vleafmodel.h
Show inline comments
 
/*
 
 *  vleafmodel.h
 
 *  mymodel
 
 *
 
 *  $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.
 
 *
 
 *  Created by Roeland Merks on 08-06-10.
 
 *  Copyright 2010 __MyCompanyName__. All rights reserved.
 
 *  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.
 
 *
 
 */
 

	
 
#ifndef _VLEAFMODEL_H_
 
#define _VLEAFMODEL_H_
 

	
 
#include <QObject>
 
#include <QtGui>
 
#include <fstream>
 
#include "simplugin.h"
 

	
 
#include "parameter.h"
 

	
 
#include "wallbase.h"
 
#include "cellbase.h"
 
#include "mymodel.h"
 
#include "flux_function.h"
 

	
 
#endif
src/wall.cpp
Show inline comments
 
@@ -28,55 +28,48 @@
 
#include <algorithm>
 
#include <QGraphicsScene>
 

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

	
 
/*! Check if this Wall still belongs to Cell a, otherwise gives it to Cell b.
 
 \return true: Wall was corrected
 
 \return false: Wall was still correct
 
 */
 
bool Wall::CorrectWall( void ) {
 
	
 
	
 
	// collect all cells to which my nodes are connected on one list
 
	list<CellBase *> owners;
 
	transform(n1->owners.begin(),n1->owners.end(), back_inserter(owners), mem_fun_ref(&Neighbor::getCell));
 
	transform(n2->owners.begin(),n2->owners.end(), back_inserter(owners), mem_fun_ref(&Neighbor::getCell));
 
	
 
	// get the list of duplicates
 
	list<CellBase *> wall_owners;
 
	owners.sort();
 
	//transform(owners.begin(), owners.end(), ostream_iterator<int>(cerr, ", "), mem_fun(&Cell::Index));
 
	duplicates_copy( owners.begin(), owners.end(), back_inserter(wall_owners) );
 
	
 
	// duplicates are the cells to which the Wall belongs
 
	/* cerr << "Wall belongs to Cells: ";
 
     transform(wall_owners.begin(), wall_owners.end(), ostream_iterator<int>(cerr, ", "), mem_fun(&Cell::Index));
 
	 cerr << endl;
 
	 */
 
	
 
	//list<Cell *>::iterator f = adjacent_find (++e,owners.end());
 
	
 
	// For the first division, wall finds three "owners", including the boundary_polygon.
 
	// Remove that one from the list.
 
	//cerr << "wall_owners.size() = " << wall_owners.size() << endl;
 
	if (wall_owners.size() == 3 && nwalls==1 /* bug-fix 22/10/2007; confine this condition to first division only */) {
 
		
 
	        #ifdef QDEBUG
 
	        qDebug() << "nwalls = " << nwalls << endl;
 
		#endif
 
		// special case for first cleavage
 
		
 
		// find boundary polygon in the wall owners list
 
		list<CellBase *>::iterator bpit = find_if (
 
												   wall_owners.begin(), wall_owners.end(), 
 
												   mem_fun( &CellBase::BoundaryPolP )
 
												   );
 
		
 
		if (bpit!=wall_owners.end()) {
 
			
 
			// add a Wall with the boundary_polygon to each cell
 
			Wall *bp_wall1 = new Wall( n2, n1, c1, (*bpit) );
 
			bp_wall1->CopyWallContents(*this);
 
			((Cell *)c1)->AddWall( bp_wall1);
 
			((Cell *)(*bpit))->AddWall(bp_wall1);
 
			
 
@@ -193,49 +186,46 @@ void Wall::ShowStructure(QGraphicsScene 
 
	Vector midline = startpoint + linevec/2.;
 
	Vector perpvec = linevec.Normalised().Perp2D();
 
	Vector textpos1 = midline + 100 * perpvec;
 
	Vector textpos2 = midline - 100 * perpvec;
 
    
 
	QGraphicsLineItem *line = new QGraphicsLineItem(0,c);
 
    
 
	line->setPen( QPen(QColor(par.arrowcolor),2) );
 
	line->setLine(startpoint.x, startpoint.y, endpoint.x, endpoint.y );
 
	line->setZValue(10);
 
	line->show();
 
    
 
	QGraphicsSimpleTextItem *text1 = new QGraphicsSimpleTextItem( QString("%1").arg(c2->Index()),0,c);
 
	QGraphicsSimpleTextItem *text2 = new QGraphicsSimpleTextItem( QString("%1").arg(c1->Index()),0,c);
 
    
 
	text1 -> setPos( textpos1.x, textpos1.y );
 
	text2 -> setPos( textpos2.x, textpos2.y );
 
	text1->setZValue(20); text2->setZValue(20);
 
	
 
	text1->setFont( QFont( "Helvetica", par.nodenumsize, QFont::Bold) );
 
	text2->setFont( QFont( "Helvetica", par.nodenumsize, QFont::Bold) );
 
    
 
	text1->setPen ( QColor(par.textcolor) );
 
	text2->setPen ( text1->pen() );
 
    
 
	//text1->setTextFlags(Qt::AlignCenter);
 
	//text2->setTextFlags(Qt::AlignCenter);
 
	text1->show(); text2->show();
 
	
 
}
 
string Wall::WallTypetoStr(const WallType &wt) const {
 
	
 
	if (wt == Normal) {
 
		return string("normal");
 
	}
 
	
 
	if (wt == AuxSource) {
 
		return string("aux_source");
 
	}
 
	
 
	if (wt == AuxSink) {
 
		return string("aux_sink");
 
	}
 
	
 
	return string("");
 
}
 

	
 

	
 

	
src/wallbase.cpp
Show inline comments
 
@@ -57,49 +57,48 @@ WallBase::WallBase(Node *sn1, Node *sn2,
 
	
 
        #ifdef QDEBUG
 
	if (sc1==sc2) { 
 
	  qDebug() << "Attempting to build a wall between identical cells: " << sc1->Index() << endl; 
 
	}
 
	#endif
 
	
 
	c1 = sc1;
 
	c2 = sc2;
 
	
 
	n1 = sn1;
 
	n2 = sn2;
 
	
 
	transporters1 = new double[CellBase::NChem()];
 
	transporters2 = new double[CellBase::NChem()];
 
	new_transporters1 = new double[CellBase::NChem()];
 
	new_transporters2 = new double[CellBase::NChem()];
 
	
 
	for (int i=0;i<CellBase::NChem();i++) {
 
		transporters1[i] = transporters2[i] = new_transporters1[i] = new_transporters2[i] = 0.;
 
	}
 
	
 
	apoplast = new double[CellBase::NChem()]; // not yet in use.
 
    
 
	//length = 0;
 
	SetLength();
 
	
 
	// to visualize flux through WallBase
 
	viz_flux=0;
 
	dead = false;
 
	wall_type = Normal;
 
	wall_index = nwalls++;
 
	
 
}
 

	
 
void WallBase::CopyWallContents(const WallBase &src) {
 
	
 
	for (int i=0; i<CellBase::NChem(); i++) {
 
		if (transporters1) {
 
			transporters1[i]=src.transporters1[i];
 
		}
 
		if (transporters2) {
 
			transporters2[i]=src.transporters2[i];
 
		}
 
		if (new_transporters1) {
 
			new_transporters1[i]=src.new_transporters1[i];
 
		}
 
		if (new_transporters2) {
 
			new_transporters2[i]=src.new_transporters2[i];
 
@@ -149,165 +148,129 @@ void WallBase::SwapWallContents(WallBase
 
			src->apoplast[i]=apoplast[i];
 
			apoplast[i]=tmp;		
 
		}
 
	}
 
	bool tmp_bool;
 
	tmp_bool = src->dead;
 
	src->dead=dead;
 
	dead = tmp_bool;
 
	
 
	WallType tmp_wall_type;
 
	tmp_wall_type = src->wall_type;
 
	src->wall_type = wall_type;
 
	wall_type = tmp_wall_type;
 
	
 
}
 

	
 
bool WallBase::SAM_P(void) { 
 
	
 
	return N1()->sam || N2()->sam; 
 
	
 
}  
 

	
 
#include <fstream>
 

	
 
/* double WallBase::Length(void){ 
 
 return (*n2 - *n1).Norm();
 
 }*/
 

	
 
void WallBase::SetLength(void) {
 
	
 
	//static bool show_nodes = true;
 
	
 
	//double old_length = length;
 
	// Step 1: find the path of nodes leading along the WallBase.
 
	// A WallBase often represents a curved cell wall: we want the total
 
	// length _along_ the wall here...
 
	
 
	// Locate first and second nodes of the edge in Cell's list of nodes
 
	list<Node *>::const_iterator first_node_edge = find(c1->nodes.begin(), c1->nodes.end(), n1);
 
	list<Node *>::const_iterator second_node_edge_plus_1 = ++find(c1->nodes.begin(), c1->nodes.end(), n2);
 
	
 
	// wrap around
 
	if (second_node_edge_plus_1 == c1->nodes.end()) {
 
		second_node_edge_plus_1 = c1->nodes.begin();
 
	}
 
	
 
	
 
	length = 0.;
 
    
 
	// Now, walk to the second node of the edge in the list of nodes
 
	stringstream deb_str;
 
	
 
	for (list<Node *>::const_iterator n=
 
		 (++first_node_edge==c1->nodes.end()?c1->nodes.begin():first_node_edge);
 
		 n!=second_node_edge_plus_1;
 
		 (++n == c1->nodes.end()) ? (n=c1->nodes.begin()):n  ) {
 
		
 
		/* if (n==c1->nodes.end()) { 
 
		 
 
		 n=c1->nodes.begin(); // wrap around
 
		 }*/
 
		
 
		list<Node *>::const_iterator prev_n = n; 
 
		if (prev_n==c1->nodes.begin()) prev_n=c1->nodes.end();
 
		--prev_n;
 
		
 
		//cerr << "Node: " << (Vector)(**n) << endl;
 
		
 
		// Note that Node derives from a Vector, so we can do vector calculus as defined in vector.h 
 
		
 
		
 
		deb_str << "[ " << (*prev_n)->index << " to " << (*n)->index << "]";
 
		
 
		length += (*(*prev_n) - *(*n)).Norm(); 
 
		
 
	}
 
	
 
	/*  if (length > 100) {
 
	 ostringstream warn;
 
	 warn << "Strange, length is " << length << "...: " << deb_str.str() << endl;
 
	 warn << "Strangeness in WallBase: " << *this << endl << endl << deb_str.str() << endl;
 
	 MyWarning::warning (warn.str().c_str());
 
	 }*/
 
	
 
	//cerr << deb_str .str() << ", length is " << length << endl;
 
	//of << length << " " << ((*n2)-(*n1)).Norm() << endl;
 
	
 
	
 
}
 

	
 
void WallBase::CorrectTransporters(double orig_length) {
 
	
 
	double length_factor = length / orig_length;
 
	// cerr << "[ lf = " << length_factor << "]";
 
	//cerr << "Correcting amount of transporters on WallBase "  << *this << ", length factor is "  << orig_length << " / " << length << endl;
 

	
 
	for (int ch=0;ch<CellBase::NChem();ch++) {
 
		transporters1[ch] *= length_factor;
 
		transporters2[ch] *= length_factor;
 
		new_transporters1[ch] *= length_factor;
 
		new_transporters2[ch] *= length_factor;
 
	}
 
	
 
}
 

	
 

	
 
Vector WallBase::VizFlux(void) {
 
	return viz_flux * ( (*n2) - (*n1) ).Normalised().Perp2D();    
 
	//return transporters1[1] * ( (*n2) - (*n1) ).Normalised().Perp2D();    
 
}
 

	
 
/* TransportFunction::TransportFunction( void ) {  
 
	
 
	//chem_change_c1 = new double[Cell::NChem()];
 
	//chem_change_c2 = new double[Cell::NChem()];
 
	
 
	//for (int i=0;i<Cell::NChem();i++) {
 
	// chem_change_c1[i] = chem_change_c2[i] = 0.;
 
	//}
 
}*/
 

	
 

	
 
void WallBase::SetTransToNewTrans( void ){ 
 
	for (int i=0;i<CellBase::NChem();i++) { 
 
		transporters1[i] = new_transporters1[i]; 
 
		transporters2[i] = new_transporters2[i]; 
 
	} 
 
}
 

	
 

	
 
Vector WallBase::getWallVector(CellBase *c) {
 
	if ( c == c1 ) {
 
		return ( Vector(*n2) - Vector(*n1) );
 
	} else {
 
		return ( Vector(*n1) - Vector(*n2) );
 
	}
 
	
 
}
 
Vector WallBase::getInfluxVector(CellBase *c) {
 
	if ( c == c1 ) {
 
		return ( Vector(*n2) - Vector(*n1) ).Normalised().Perp2D();
 
	} else {
 
		return ( Vector(*n1) - Vector(*n2) ).Normalised().Perp2D();
 
	}
 
}
 

	
 
//! \brief Test if this wall intersects with division plane p1 -> p2 
 
bool WallBase::IntersectsWithDivisionPlaneP(const Vector &p1, const Vector &p2) {
 
	
 
	// Algorithm of http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/
 
	double x1 = n1->x, y1 = n1->y;
 
	double x2 = n2->x, y2 = n2->y;
 
	double x3 = p1.x, y3 = p1.y;
 
	double x4 = p2.x, y4 = p2.y;
 
	
 
	double ua = ( (x4 - x3) * (y1-y3) - (y4 - y3)*(x1-x3) ) / ( (y4 -y3) * (x2 -x1) - (x4-x3)*(y2-y1));
 
	//	double ub = ( (x2 - x1) * (y1 - y3)  - (y2 - y1) * (x1 -x3) ) / ( ( y4-y3) * (x2-x1) - (x4-x3)*(y2-y1)) ;
 
	
 
	// If ua is between 0 and 1, line p1 intersects the line segment
 
	if ( ua >=0. && ua <=1.) return true;
 
	else return false;
 
	
 
}
 

	
 

	
 

	
src/wallbase.h
Show inline comments
 
@@ -170,78 +170,32 @@ public:
 
	}
 
	inline double getApoplast(int ch) const { return apoplast[ch]; }
 
	inline void setApoplast(int ch, double val) { apoplast[ch] = val; }
 
	inline CellBase *getOtherCell(CellBase *c) { return c1 == c ? c2 : c1; }
 
	Vector getInfluxVector(CellBase *c);
 
	Vector getWallVector(CellBase *c);
 
	void CorrectTransporters(double orig_length);
 
	
 
	inline double Length(void) { return length; }
 
	//double Length(void);
 
	
 
	ostream &print(ostream &os) const; 
 
		
 
	void SetLength(void);
 
	void Transport(void);
 
	
 
	inline void setVizFlux( double value ) { viz_flux = value; } 
 
	
 
	/*! Return vector containing the directional flux through the wall.
 
	 as defined by the value "viz_flux" which is supplied by the end-user
 
	 in the TransportFunction.
 
	 */
 
	Vector VizFlux(void);
 
	bool IntersectsWithDivisionPlaneP(const Vector &p1, const Vector &p2);
 
	
 
	/*! Function to be defined in leaf.cpp */
 
	//void OnWallInsert(void);
 
	
 
	
 

	
 
	void SetTransToNewTrans( void );
 
	
 
	// implemented in xmlwrite.cpp
 
	//void XMLAdd(xmlNode *parent) const;
 
private:
 
	
 
};
 

	
 
/* class TransportFunction {
 
	
 
	friend class Mesh;
 
public:
 
	TransportFunction( void );
 
	virtual ~TransportFunction() {
 
		//delete[] chem_change_c1;
 
		//delete[] chem_change_c2;
 
	}
 
	virtual void operator()(WallBase *w, double *dchem_c1, double *dchem_c2) = 0;// { cerr << "This is base class TransportFunction.\n"; }
 
	//virtual void operator()(WallBase *w, double *dchem_c1, double *dchem_c2, double *dapo) =0;
 
protected:
 
	int wall_index; //double *chem_change_c1;
 
	//double *chem_change_c2;
 
};
 

	
 
class CellReaction {
 
	
 
public:
 
	CellReaction(void) {};
 
	virtual ~CellReaction() {};
 
	
 
	//! Implements the actual, intracellular chemical reactions.
 
	virtual void operator()(CellBase * c, double *dchem ) = 0;
 
	
 
};
 

	
 
class WallReaction {
 
	
 
public:
 
	WallReaction(void) {};
 
	virtual ~WallReaction() {};
 
	
 
	//! Implements the actual, biochemical reactions occuring at the wall.
 
	virtual void operator()(WallBase *, double *dw1, double *dw2) = 0;
 
	
 
};*/
 

	
 
ostream &operator<<(ostream &os, const WallBase &w);
 
#endif
src/wallitem.cpp
Show inline comments
 
@@ -16,161 +16,115 @@
 
 *  along with the Virtual Leaf.  If not, see <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include <QDebug>
 
#include <string>
 
#include <QGraphicsScene>
 
#include <QVector>
 
#include "canvas.h"
 
#include "wallitem.h"
 
#include "parameter.h"
 
#include "node.h"
 
#include "transporterdialog.h"
 

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

	
 
WallItem::WallItem( Wall *w, int wallnumber, QGraphicsScene *canvas )
 
  : QGraphicsLineItem( 0, canvas ), SimItemBase( w, canvas){
 

	
 
  wn = wallnumber;
 

	
 
  extern Parameter par;
 
  //Wall *w=&getWall();
 
  
 
  // Draw amount of "PIN1"
 
  //double val = wn==1?(w->Transporters1(1)/par.Pi_tot)*255.:(w->Transporters2(1)/par.Pi_tot)*255.;
 
  
 
  /* if (val > 255 || val < 0 ) { 
 
     std::cerr << "val = " << val << endl;
 
     if (wn == 1) {
 
     std::cerr << "Transporters1(1) = " << w->Transporters1(1) << endl;
 
     } else {
 
     std::cerr << "Transporters2(1) = " << w->Transporters2(1) << endl;
 
     }
 
    
 
     }*/
 
  
 
  
 

	
 
	  setColor();
 
  
 
	  // line with "PIN1"is a bit inside the cell wall
 
	  Vector edgevec = (*(w->N2())) - (*(w->N1()));
 
	  Vector perp = edgevec.Normalised().Perp2D();
 
	  
 
	  Vector offs = Cell::Offset();
 
	  double factor = Cell::Factor();
 
	  
 
	  Vector from = ( offs + *(w->N1()) ) * factor + (wn==1?-1:1) * par.outlinewidth * 0.5 * factor * perp;
 
	  Vector to = ( offs + *(w->N2()) ) *factor + (wn==1?-1:1) * par.outlinewidth * 0.5 * factor * perp;
 
	  
 
	  
 
	  Vector tmp_centroid = ( *(w->N2()) + *(w->N1()) )/2.;
 
	  Vector centroid = ( offs + tmp_centroid ) * factor;
 
	  
 
	  QString text=QString("%1").arg(w->Index());
 

	
 
	  /*  if (0) {
 
		  QGraphicsSimpleTextItem *ctext = new QGraphicsSimpleTextItem ( text, 0, canvas );
 
		  ctext->setPen( QPen(QColor("orange")) );
 
		  ctext->setZValue(20);
 
		  ctext->setFont( QFont( "Helvetica", par.nodenumsize, QFont::Bold) );
 
		  //ctext->setTextFlags(Qt::AlignCenter);
 
		  ctext->show();
 
		  ctext ->setPos(centroid.x,
 
						 centroid.y );
 
	  }*/
 
	  
 
	  setLine(( from.x ),
 
			  ( from.y ),
 
			  ( to.x ),
 
			  ( to.y ) );
 
	  setZValue(12);
 
  }
 

	
 

	
 
void WallItem::setColor(void) {
 

	
 
  QColor diffcolor;
 
  static const QColor purple("Purple");
 
  static const QColor blue("blue");
 
  
 
  Wall *w=&getWall();
 
  double tr = wn==1?w->Transporters1(1):w->Transporters2(1);
 
  CellBase *c = wn==1?w->C1():w->C2();
 
  diffcolor.setRgb( (int)( ( tr / (1 + tr) )*255.), 0, 0);
 
  //diffcolor.setRgb( (int)( ((wn==1?w->Transporters1(1):w->Transporters2(1)))*255.), 0, 0);
 
  /* if (wn==1) {
 
     cerr << "Transporter: " << w->Transporters1(1) << endl;
 
     } else {
 
     cerr << "Transporter: " << w->Transporters2(1) << endl;
 
     }*/
 
  
 
  if (w->AuxinSource() && c->BoundaryPolP()) {
 
    setPen( QPen(purple , par.outlinewidth) );
 
  } else {
 
    if (w->AuxinSink() && c->BoundaryPolP()) {
 
      setPen( QPen(blue, par.outlinewidth));
 
    } else {
 
      setPen (QPen(diffcolor, par.outlinewidth) );
 
    }
 
  }
 
  
 
//   if (c->BoundaryPolP()) {
 
//     setPen(QPen(QColor("red"), 20));
 
//   }
 
}
 

	
 
void WallItem::OnClick(QMouseEvent *e) {
 
  
 

	
 
	Wall *w=&getWall();
 
	#ifdef QDEBUG
 
	qDebug() << "Wall ID = " << w->Index() << ", this = " << w << endl;
 
	qDebug() << "Wall item = " << this << endl;
 
	qDebug() << "C1 = " << w->C1()->Index() << ", C2 = " << w->C2()->Index() << endl;
 
	qDebug() << "N1 = " << w->N1()->Index() << ", N2 = " << w->N2()->Index() << endl;
 
	#endif
 
	//double tr = wn==1?w->Transporters1(1):w->Transporters2(1);
 
	CellBase *c = wn==1?w->C1():w->C2();
 

	
 
	TransporterDialog dialog(w, c, wn);
 
	dialog.exec();
 

	
 
	if (e->button() == Qt::RightButton) {
 
		QString message;
 
		if (wn==1) {
 
			message=QString("Transporter 1 = %1, color = %2, length = %3\n").arg(w->Transporters1(1)).arg(pen().color().red()).arg(getWall().Length());
 
		} else {
 
			message=QString("Transporter 2 = %1, color = %2, length = %3\n").arg(w->Transporters2(1)).arg(pen().color().red()).arg(getWall().Length());
 
		}
 
		
 
		//extern MainBase *main_window;
 
		//((Main *)main_window)->UserMessage(message);
 
		
 
	} else {
 
		if (e->button() == Qt::LeftButton) {
 
			if (c->BoundaryPolP()) {
 
				w->cycleWallType();
 
			} else {
 
				if (e->modifiers() == Qt::ShiftModifier) {
 
					wn==1?w->setTransporters1(1,0):w->setTransporters2(1,0);					
 
					
 
				} else {
 
					// set high amount of PIN1
 
					//cerr << "Setting PIN1\n";
 
					wn==1?w->setTransporters1(1,10):w->setTransporters2(1,10);
 
				}
 
			}
 
			setColor();
 
			update(boundingRect());
 
		} 
 
		/* else {
 
			if (e->button() == Qt::MidButton && (e->modifiers == Qt::ShiftModifier & Qt::ControlModifier)) {
 
				// hidden feature for correcting 
 
			}*/
 
		
 
	
 
	}
 
}
src/wallitem.h
Show inline comments
 
@@ -21,32 +21,30 @@
 
 *
 
 */
 

	
 

	
 
#ifndef _WALLITEM_H_
 
#define _WALLITEM_H_
 

	
 
#include <QGraphicsScene>
 
#include <QGraphicsLineItem>
 
#include <QPainter>
 
#include <qpainter.h>
 
#include <QMouseEvent>
 
#include "simitembase.h"
 
#include "wall.h"
 

	
 
//! Shows transporter concentrations at one side of the wall
 

	
 
class WallItem : public QGraphicsLineItem, public SimItemBase
 
{
 
public:
 
  WallItem( Wall *n, int wallnumber, QGraphicsScene *canvas );
 
  virtual ~WallItem() {}
 
  Wall &getWall(void) const { return *class_cast<Wall*>(obj); }
 
  void OnClick(QMouseEvent *e);  
 
  //virtual void userMove(double dx, double dy);  
 
  //virtual void paint( QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0);
 
  void setColor(void);
 
 private:
 
  int wn;
 
};
 

	
 
#endif
src/warning.cpp
Show inline comments
 
@@ -45,50 +45,48 @@ void MyWarning::error(char * fmt, ...)
 
    va_list ap;
 

	
 
    va_start(ap, fmt);
 
    vfprintf(stderr, fmt, ap);		/* invoke interface to printf       */
 
    fprintf(stderr,"\n");     /* automatic \n by Roeland */
 
    fflush(stderr);			/* drain std error buffer 	    */
 
    va_end(ap);
 
    exit(1);				/* quit with error status	    */
 
}
 
#else
 
//#include <qmessagebox.h>
 
#include "UniqueMessage.h"
 
void MyWarning::error(const char *fmt, ...)
 
{
 
  va_list ap;
 
  if (Quiet) return;
 
  char *message = new char[1000];
 
 
 
  va_start(ap, fmt);
 
  vsnprintf(message, 999, fmt, ap);		/* invoke interface to printf       */
 
  va_end(ap);
 
  
 
  QString qmess(message);
 
  
 
  //  bool batch = false;
 
  
 
  if (qApp->type()==QApplication::Tty) {
 
    // batch mode: print the message to stderr
 
    fprintf(stderr, "Fatal error: %s\n",qmess.toStdString().c_str());
 
    exit(1);
 
  } else { // issue a dialog box
 
    /* Solve this with signal and slot...! */
 
	  //extern MainBase *main_window;
 
    //((Main *)main_window)->stopSimulation();
 
    
 
	QMessageBox::critical( 0 , "Fatal error", qmess, QMessageBox::Abort, QMessageBox::NoButton, QMessageBox::NoButton );
 
    fprintf(stderr, "Error: %s\n",qmess.toStdString().c_str());
 
    QCoreApplication::exit(1);
 
    std::exit(1);
 
  }
 
  delete[] message;
 
  
 
}
 
#endif
 

	
 

	
 
/*
 
 * EPRINTF: scream, but don't die yet.
 
 * Roeland changed this to "warning" (21/10/1998)
 
 * and added an automatic "\n"
src/warning.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
 
 *  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.
 
 *
 
 */
 
 
 
#ifndef _WARNING_H_
 
#define _WARNING_H_
 
 
#define MEMORYCHECK(x) if ((x)==NULL) {   fprintf(stderr, "Out of Memory error in "#x" \n");  exit(0); }
 
 
#define UNIDENTIFIED 2353996
 
//static int last_value=UNIDENTIFIED;
 
/*#define WATCH(x) if (last_value==UNIDENTIFIED) {   last_value=x; 
 
} else { if (x!=last_value) { fprintf(stderr,"WATCH value changed. Suspending execution. \n Interrupt within debugger to examine position in program.\n"); 
 
				 last_value=x; 
 
				 while(1);
 
	   } else { 
 
		      last_value=x;
 
	   } 
 
	   }*/
 
 
 
/* These functions were a gift from Josh Barnes */
 
/* I changed the name "eprintf" to "warning" */
 
 
#ifdef __cplusplus 
 
extern "C" { 
 
#endif
 
  // namespace MyWarning needed because libxml2 also defines a warning token.
 
    
 
  namespace MyWarning {
 
    void error(const char *, ...);
 
    void warning(const char *, ...);
 
    void unique_warning(const char *, ...);
 
  }
 
  
 
#ifdef __cplusplus
 
}
 
#endif
 
 
#endif
 
/*
 
 *
 
 *  $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.
 
 *
 
 */
 

	
 

	
 
#ifndef _WARNING_H_
 
#define _WARNING_H_
 

	
 
#define MEMORYCHECK(x) if ((x)==NULL) {   fprintf(stderr, "Out of Memory error in "#x" \n");  exit(0); }
 

	
 
#define UNIDENTIFIED 2353996
 

	
 
#ifdef __cplusplus 
 
extern "C" { 
 
#endif
 
  // namespace MyWarning needed because libxml2 also defines a warning token.
 
    
 
  namespace MyWarning {
 
    void error(const char *, ...);
 
    void warning(const char *, ...);
 
    void unique_warning(const char *, ...);
 
  }
 
  
 
#ifdef __cplusplus
 
}
 
#endif
 

	
 
#endif
src/xmlwrite.cpp
Show inline comments
 
@@ -166,49 +166,48 @@ void Cell::XMLAddCore(xmlNodePtr xmlcell
 
    ostringstream text;
 
    text << div_counter;
 
    xmlNewProp(xmlcell, BAD_CAST "div_counter", BAD_CAST text.str().c_str());
 
  }
 
  
 
	{ 
 
		ostringstream text;
 
		text << cell_type;
 
		xmlNewProp(xmlcell, BAD_CAST "cell_type", BAD_CAST text.str().c_str());
 
	}
 
    
 
  for (list<Node *>::const_iterator i=nodes.begin();i!=nodes.end();i++) {
 
    {
 
      ostringstream text;
 
      xmlNodePtr node_xml = xmlNewChild(xmlcell, NULL, BAD_CAST "node", NULL);
 
      text << (*i)->Index();
 
      xmlNewProp(node_xml, BAD_CAST "n", BAD_CAST text.str().c_str());
 
    }
 
  }
 

	
 
  for (list<Wall *>::const_iterator i=walls.begin();i!=walls.end();i++) {
 
    {
 
      ostringstream text;
 
      xmlNodePtr wall_xml = xmlNewChild(xmlcell, NULL, BAD_CAST "wall", NULL);
 
      //text <<wall_list_index( *i );
 
      text << XMLIO::list_index( m->walls.begin(), m->walls.end(), *i );
 
      xmlNewProp(wall_xml, BAD_CAST "w", BAD_CAST text.str().c_str());
 
    }
 
  }
 

	
 
  
 
  
 
  
 
  xmlNodePtr chem_xml = xmlNewChild(xmlcell, NULL, BAD_CAST "chem", NULL); 
 
  {
 
    ostringstream text;
 
    text << NChem();
 
    xmlNewProp(chem_xml, BAD_CAST "n", BAD_CAST text.str().c_str());
 
  }
 
  
 
  for (int i=0;i<NChem();i++) {
 
    xmlNodePtr chem_val_xml = xmlNewChild(chem_xml, NULL, BAD_CAST "val", NULL);
 
    { 
 
      ostringstream text;
 
      text << chem[i];
 
      xmlNewProp(chem_val_xml, BAD_CAST "v", BAD_CAST text.str().c_str());
 

	
 
    }
 
  }
 
@@ -341,137 +340,130 @@ int Cell::XMLRead(xmlNode *cur)  {
 
      
 
  int nnodes = tmp_nodes.size();
 
  for (int i=0;i<nnodes;i++) {
 
    m->AddNodeToCell( this, 
 
		      m->nodes[tmp_nodes[i]], 
 
		      m->nodes[tmp_nodes[(nnodes+i-1)%nnodes]],
 
		      m->nodes[tmp_nodes[(i+1)%nnodes]] );
 
	
 
  }
 

	
 
  n = cur->xmlChildrenNode;
 
  while(n!=NULL) {
 
	  if ((!xmlStrcmp(n->name, (const xmlChar *)"chem"))) {
 

	
 
	    xmlNode *v_node = n->xmlChildrenNode;
 
	    int nv=0;
 
	    while (v_node!=NULL) {
 
	      if ((!xmlStrcmp(v_node->name, (const xmlChar *)"val"))) {
 
		
 
		
 
		if (nv>=Cell::NChem()) {
 
		  {
 
		    stringstream text;
 
		    text << "Exception in Mesh::XMLRead: Too many chemical values given for cell(s). Ignoring remaining values.";
 
		    //ThrowStringStream(text);
 
		    unique_warning(text.str().c_str());
 
		    break;
 
		  }
 
		}
 
		
 
		xmlChar *nc = xmlGetProp(v_node, (const xmlChar *) "v");
 
		
 
		if (nc==0) {
 
		  unique_warning("Token \"v\" not found in xmlwrite.cpp at or around line no. 1002");
 
		}
 
		//double v = strtod( (char *)nc, 0 );
 
		double v=standardlocale.toDouble((char *)nc, &ok);
 
		if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(char *)nc);
 
		chem[nv++]=v;
 
		xmlFree(nc);
 
	      }
 
	      v_node = v_node->next; 
 
	    }
 
	  }
 
	  n = n->next;
 
  }
 
	
 
	// read cell properties
 
	{
 
		xmlChar *v_str = xmlGetProp(cur, BAD_CAST "area");
 
		
 
		if (v_str==0) {
 
			unique_warning("Token \"area\" not found in xmlwrite.cpp at or around line no. 1018");
 
		}
 
		if (v_str != NULL) {
 
		  //area = strtod( (char *)v_str, 0);
 
			area=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 "target_area");
 
		
 
		if (v_str==0) {
 
			unique_warning("Token \"target_area\" not found in xmlwrite.cpp at or around line no. 1029");
 
		}
 
    if (v_str != NULL) {
 
      //target_area = strtod( (char *)v_str, 0);
 
      	target_area=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 "target_length");
 

	
 
    if (v_str==0) {
 
      unique_warning("Token \"target_length\" not found in xmlwrite.cpp at or around line no. 1041");
 
    }
 
    if (v_str != NULL) {
 
      //target_length = strtod( (char *)v_str, 0);
 
      target_length=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 "lambda_celllength");
 

	
 
    if (v_str==0) {
 
      unique_warning("Token \"lambda_celllength\" not found in xmlwrite.cpp at or around line no. 1052");
 
    }
 
    if (v_str != NULL) {
 
      //lambda_celllength = strtod( (char *)v_str, 0);
 
      lambda_celllength=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 "stiffness");
 

	
 
    if (v_str==0) {
 
      unique_warning("Token \"stiffness\" not found in xmlwrite.cpp at or around line no. 1063");
 
    }
 
    if (v_str != NULL) {
 
      //stiffness = strtod( (char *)v_str, 0);
 
      stiffness=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 "fixed");
 

	
 
    if (v_str==0) {
 
      unique_warning("Token \"fixed\" not found in xmlwrite.cpp at or around line no. 1075");
 
    }
 
    if (v_str != NULL) {
 
      fixed = strtobool( (char *)v_str);
 
      xmlFree(v_str);
 
    }
 
  }
 

	
 
  {
 
    xmlChar *v_str = xmlGetProp(cur, BAD_CAST "pin_fixed");
 

	
 
    if (v_str==0) {
 
      unique_warning("Token \"pin_fixed\" not found in xmlwrite.cpp at or around line no. 1086");
 
@@ -577,54 +569,48 @@ void NodeSet::XMLRead(xmlNode *root, Mes
 
      if (nc==0) {
 
	unique_warning("Token \"n\" not found in xmlwrite.cpp at or around line no. 966");
 
      }
 
      tmp_nodes.push_back(atoi( (char *)nc));
 
      xmlFree(nc);
 
    }
 
    n = n->next;
 
  }
 
  
 
  int nnodes = tmp_nodes.size();
 
  for (int i=0;i<nnodes;i++) {
 
    AddNode( &(m->getNode(tmp_nodes[i])) );
 
  }
 
  
 
}
 

	
 

	
 

	
 

	
 
void Wall::XMLAdd(xmlNode *parent) const { 
 
  
 
  // Save the node to a stream so we can reconstruct its state later
 
  xmlNodePtr xmlwall = xmlNewChild(parent, NULL, BAD_CAST "wall",NULL);
 
  
 
  /* {
 
     ostringstream text;
 
     text << index;
 
     xmlNewProp(xmlnode, BAD_CAST "index", BAD_CAST text.str().c_str());
 
     }*/
 
  
 
  {
 
    ostringstream text;
 
    text << Index();
 
    xmlNewProp(xmlwall, BAD_CAST "index" , BAD_CAST text.str().c_str() );
 
  }
 

	
 
  {
 
    ostringstream text;
 
    text << c1->Index();
 
    xmlNewProp(xmlwall, BAD_CAST "c1", BAD_CAST text.str().c_str());
 
  }
 
  
 
  
 
  {
 
    ostringstream text;
 
    text << c2->Index();
 
    xmlNewProp(xmlwall, BAD_CAST "c2", BAD_CAST text.str().c_str());
 
  }
 
  
 

	
 
  {
 
    ostringstream text;
 
    text << n1->Index();
 
    xmlNewProp(xmlwall, BAD_CAST "n1", BAD_CAST text.str().c_str());
 
@@ -636,54 +622,48 @@ void Wall::XMLAdd(xmlNode *parent) const
 
    xmlNewProp(xmlwall, BAD_CAST "n2", BAD_CAST text.str().c_str());
 
  }
 

	
 
  {
 
    ostringstream text;
 
    text << length;
 
    xmlNewProp(xmlwall, BAD_CAST "length", BAD_CAST text.str().c_str());
 
  }
 
    
 

	
 
  {
 
    ostringstream text;
 
    text << viz_flux;
 
    xmlNewProp(xmlwall, BAD_CAST "viz_flux", BAD_CAST text.str().c_str());
 
  }
 

	
 
  {
 
    ostringstream text;
 
    text << WallTypetoStr(wall_type);
 
    xmlNewProp(xmlwall, BAD_CAST "wall_type", BAD_CAST text.str().c_str());
 
  }
 
      
 
    
 
  xmlNodePtr tr1_xml = xmlNewChild(xmlwall, NULL, BAD_CAST "transporters1", NULL); 
 
  //   {
 
  //     ostringstream text;
 
  //     text << Cell::nchem;
 
  //     xmlNewProp(tr1_xml, BAD_CAST "n", BAD_CAST text.str().c_str());
 
  //   }
 
  
 
  if (transporters1) {
 
    for (int i=0;i<Cell::NChem();i++) {
 
      xmlNodePtr tr1_val_xml = xmlNewChild(tr1_xml, NULL, BAD_CAST "val", NULL);
 
      { 
 
	ostringstream text;
 
	text << transporters1[i];
 
	xmlNewProp(tr1_val_xml, BAD_CAST "v", BAD_CAST text.str().c_str());
 
      
 
      }
 
    }
 
  }
 
  if (transporters2) {
 
    xmlNodePtr tr2_xml = xmlNewChild(xmlwall, NULL, BAD_CAST "transporters2", NULL); 
 
  
 
    for (int i=0;i<Cell::NChem();i++) {
 
      xmlNodePtr tr2_val_xml = xmlNewChild(tr2_xml, NULL, BAD_CAST "val", NULL);
 
      { 
 
	ostringstream text;
 
	text << transporters2[i];
 
	xmlNewProp(tr2_val_xml, BAD_CAST "v", BAD_CAST text.str().c_str());
 
      
 
      }
 
    }
 
  }
 
@@ -732,65 +712,65 @@ void Mesh::XMLSave(const char *docname, 
 
	
 
	// based on libxml2 example code "tree2.c"
 
	
 
	xmlDocPtr doc = NULL;       /* document pointer */
 
	xmlNodePtr root_node = NULL;/* node pointers */
 
	//xmlDtdPtr dtd = NULL;       /* DTD pointer */
 
	
 
	//  LIBXML_TEST_VERSION;
 
	
 
	/* 
 
	 * Creates a new document, a node and set it as a root node
 
	 */
 
	doc = xmlNewDoc(BAD_CAST "1.0");
 
	root_node = xmlNewNode(NULL, BAD_CAST "leaf");
 
	xmlDocSetRootElement(doc, root_node);
 
	
 
	/* 
 
	 * xmlNewProp() creates attributes, which is "attached" to an node.
 
	 * It returns xmlAttrPtr, which isn't used here.
 
	 */
 
	xmlNewProp(root_node, BAD_CAST "name", BAD_CAST docname);
 
	
 
	time_t t;
 
	std::time(&t);
 
	// asctime_r(localtime(&t),tstring); //Doesn't work for MinGW
 

	
 
	char *tstring = strdup(asctime(localtime(&t))); // but this does
 
	// replace "end of line character by '\0'
 
	char *eol=strchr(tstring,'\n');
 
	if (eol!=NULL)
 
		*eol='\0';
 
	
 
	xmlNewProp(root_node, BAD_CAST "date", BAD_CAST tstring);
 
	free(tstring);
 
	
 
	
 
	QString simtime = QString("%1").arg(time);
 
	xmlNewProp(root_node, BAD_CAST "simtime", BAD_CAST simtime.toStdString().c_str()); 
 
	/*
 
	 * Creates a DTD declaration. Isn't mandatory. 
 
	 */
 
	//dtd = xmlCreateIntSubset(doc, BAD_CAST "root", NULL, BAD_CAST "tree2.dtd");
 

	
 
	par.XMLAdd(root_node);
 

	
 
	xmlNodePtr xmlnodes = xmlNewChild(root_node, NULL, BAD_CAST "nodes",NULL);
 
	{ ostringstream text;
 
		text << NNodes();
 
		xmlNewProp(xmlnodes, BAD_CAST "n", BAD_CAST text.str().c_str());
 
	}
 
	
 
	{ ostringstream text;
 
		text << Node::target_length;
 
		xmlNewProp(xmlnodes, BAD_CAST "target_length", BAD_CAST text.str().c_str());
 
	}
 
	
 
	
 
	
 
	for (vector<Node *>::const_iterator i=nodes.begin();
 
		 i!=nodes.end();
 
		 i++) {
 
		(*i)->XMLAdd(xmlnodes) ;
 
	}
 
	
 
	
 
	/* 
 
	 * xmlNewChild() creates a new node, which is "attached" as child node
 
@@ -875,145 +855,147 @@ void Mesh::XMLSave(const char *docname, 
 
		xmlAddChild(root_node, options);
 
	}
 
	
 
	
 
	
 
	
 
	/* 
 
	 * Dumping document to stdio or file
 
	 */
 
	xmlSetDocCompressMode(doc,9);
 
	xmlSaveFormatFileEnc(docname, doc, "UTF-8", 1);
 
	
 
	/*free the document */
 
	xmlFreeDoc(doc);
 
	
 
	/*
 
	 *Free the global variables that may
 
	 *have been allocated by the parser.
 
	 */
 
	xmlCleanupParser();
 
	
 
	/*
 
	 * this is to debug memory for regression tests
 
	 */
 
	//xmlMemoryDump();
 
}
 

	
 

	
 

	
 
void Mesh::XMLReadSimtime(const xmlNode *a_node) {
 
	
 
  xmlNode *root_node;
 
  root_node = (xmlNode *)a_node;
 
  xmlChar *strsimtime = xmlGetProp(root_node, BAD_CAST "simtime");
 
  
 
  
 
  if (strsimtime) {
 
    //double simtime = strtod((const char *)strsimtime, 0);
 

	
 
    QLocale standardlocale(QLocale::C);
 
    bool ok;
 
    
 
    double simtime=standardlocale.toDouble((char *)strsimtime, &ok);
 
    if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(char *)strsimtime);
 
      time = simtime;
 
		cerr << "Simtime = " << strsimtime << endl;
 
#ifdef QDEBUG
 
                qDebug() << "Simtime = " << strsimtime << endl;
 
#endif
 
	} else {
 
		cerr << "No simtime found in file \n";
 
#ifdef QDEBUG
 
    qDebug() << "No simtime found in file." << endl;
 
#endif
 
		time =0;
 
	}	
 
}
 

	
 
void Mesh::XMLReadPars(const xmlNode * a_node) {
 
	xmlNode *root_node;
 
	root_node = (xmlNode *)a_node;
 
	par.XMLRead(root_node);
 
	Seed(par.rseed);
 
	MakeDir(par.datadir);
 
}
 

	
 
void Mesh::XMLReadGeometry(const xmlNode * a_node)
 
{
 
  
 
	xmlNode *root_node;
 
	root_node = (xmlNode *)a_node;
 
	xmlNode *cur;
 
	QLocale standardlocale(QLocale::C);
 
	bool ok;
 
	// allocate Nodes
 
	cur = root_node->xmlChildrenNode;
 
	while (cur!=NULL) {
 
		if ((!xmlStrcmp(cur->name, (const xmlChar *)"nodes"))){
 
			XMLReadNodes(cur);
 
		}
 
		cur=cur->next;
 
	}
 
	
 
	cur = root_node->xmlChildrenNode;
 
	while (cur!=NULL) {
 
		if ((!xmlStrcmp(cur->name, (const xmlChar *)"nodesets"))) {
 
			XMLReadNodeSets(cur);
 
		}
 
		cur=cur->next;
 
	}
 
	
 
	cur=root_node->xmlChildrenNode;
 
	while (cur!=NULL) {
 
		if ((!xmlStrcmp(cur->name, (const xmlChar *)"nodes"))) {
 
			XMLReadNodeSetsToNodes(cur);
 
		}
 
		cur = cur->next;
 
	}
 
    
 
	//cur = root_node;
 
    
 
	// allocate Cells
 
	cur = root_node;
 
	
 
	// allocate Cells
 
	cur = cur->xmlChildrenNode;
 
	while (cur!=NULL) {
 
		if ((!xmlStrcmp(cur->name, (const xmlChar *)"cells"))){
 
			xmlChar *offsetxc = xmlGetProp(cur, BAD_CAST "offsetx");
 
			xmlChar *offsetyc = xmlGetProp(cur, BAD_CAST "offsety");
 
			//double ox = strtod((const char*)offsetxc, 0);
 

	
 
			double ox=standardlocale.toDouble((const char *)offsetxc, &ok);
 
			if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(const char *)offsetxc);
 
			//double oy = strtod((const char*)offsetyc, 0);
 

	
 
			double oy=standardlocale.toDouble((const char *)offsetyc, &ok);
 
			if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(const char *)offsetyc);
 
			Cell::setOffset(ox, oy);
 
			xmlFree(offsetxc);
 
			xmlFree(offsetyc);
 
			
 
			xmlChar *magnificationc = xmlGetProp(cur, BAD_CAST "magnification");
 
			//Cell::SetMagnification(strtod((const char*)magnificationc, 0 ));
 

	
 
			Cell::SetMagnification(standardlocale.toDouble((const char *)magnificationc, &ok));
 
			if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(const char *)magnificationc);
 
			xmlFree(magnificationc);
 
			
 
			xmlChar *baseareac = xmlGetProp(cur, BAD_CAST "base_area");
 
			//Cell::BaseArea()= strtod((const char *)baseareac, 0 );
 

	
 
			Cell::BaseArea() = standardlocale.toDouble((const char *)baseareac, &ok);
 
			if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(const char *)baseareac);
 
			xmlFree(baseareac);
 
			
 
			
 
			XMLReadCells(cur);
 
		}
 
		cur=cur->next;
 
	}
 
    
 
	// allocate Walls (we need to have read the cells before constructing walls)
 
	vector <Wall *> tmp_walls;
 
	cur = root_node->xmlChildrenNode;
 
	while (cur!=NULL) {
 
		if ((!xmlStrcmp(cur->name, (const xmlChar *)"walls"))){
 
			XMLReadWalls(cur, &tmp_walls);
 
		}
 
		cur=cur->next;
 
	}
 
	
 
	// read walls to cells and boundary_polygon
 
	cur = root_node->xmlChildrenNode;
 
	while (cur!=NULL) {
 
		if ((!xmlStrcmp(cur->name, (const xmlChar *)"cells"))) {
 
@@ -1050,200 +1032,197 @@ void Mesh::XMLParseTree(const xmlNode *r
 
	
 
}
 

	
 

	
 
void Mesh::XMLReadNodes(xmlNode *root) {
 
	
 
  QLocale standardlocale(QLocale::C);
 
  bool ok;
 

	
 
  xmlNode *cur = root;
 
  cur = cur->xmlChildrenNode;
 
	
 
  for (vector<Node *>::iterator i=nodes.begin();
 
       i!=nodes.end();
 
       i++) {
 
    delete *i;
 
  }
 
	
 
  nodes.clear();
 
  Node::nnodes=0;
 
	
 
  xmlChar *tlc = xmlGetProp(root, BAD_CAST "target_length");
 
	
 
  if (tlc != 0) {
 
    //Node::target_length = strtod( (const char *)tlc, 0 );
 

	
 
	  
 
    Node::target_length = standardlocale.toDouble((const char *)tlc, &ok);
 
    if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(const char *)tlc);
 
		
 
    xmlFree(tlc);
 
  } else {
 
    // note that libxml2 also defines a token "warning"
 
    MyWarning::unique_warning("Warning: value found in XML file for Node::target_length.");
 
  }
 
    
 
  while (cur!=NULL) {
 
    if ((!xmlStrcmp(cur->name, (const xmlChar *)"node"))){
 
			
 
      xmlChar *xc = xmlGetProp(cur, BAD_CAST "x");
 
			
 
      if (xc==0) {
 
	unique_warning("Token \"x\" not found in xmlwrite.cpp at or around line no. 722");
 
      }
 
			
 
      xmlChar *yc = xmlGetProp(cur, BAD_CAST "y");
 
			
 
      if (yc==0) {
 
	unique_warning("Token \"y\" not found in xmlwrite.cpp at or around line no. 727");
 
      }
 
			
 
      xmlChar *fixedc = xmlGetProp(cur, BAD_CAST "fixed");
 
      if (fixedc==0) {
 
	unique_warning("Token \"fixed\" not found in xmlwrite.cpp at or around line.");
 
      }
 
			
 
      xmlChar *boundaryc = xmlGetProp(cur, BAD_CAST "boundary");
 
      if (boundaryc==0) {
 
	unique_warning("Token \"boundary\" not found in xmlwrite.cpp at or around line.");
 
      }
 
			
 
      xmlChar *samc = xmlGetProp(cur, BAD_CAST "sam");
 
      if (samc==0) {
 
	unique_warning("Token \"sam\" not found in xmlwrite.cpp at or around line.");
 
      }
 
			
 
      //double x = strtod( (char *)xc , 0);
 

	
 
      double x = standardlocale.toDouble((const char *)xc, &ok);
 
      if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(const char *)xc);
 
		
 
      //double y = strtod( (char *)yc , 0 );
 
      double y = standardlocale.toDouble((const char *)yc, &ok);
 
      if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(const char *)yc);
 
			
 
      Node *new_node = new Node(x,y);
 
      nodes.push_back(new_node);
 
			
 
      new_node->m = this;
 
      new_node->fixed = strtobool( (char *)fixedc);
 
      new_node->boundary = strtobool( (char *)boundaryc );
 
      new_node->sam = strtobool ( (char *)samc);
 
      new_node->node_set = 0;
 
			
 
      xmlFree(xc);
 
      xmlFree(yc);
 
      xmlFree(boundaryc);
 
      xmlFree(fixedc);
 
      xmlFree(samc);
 
			
 
			
 
    }
 
    cur=cur->next;
 
  }
 
	
 
  shuffled_nodes.clear();
 
  shuffled_nodes = nodes;
 
	
 
  MyUrand r(shuffled_nodes.size());
 
  random_shuffle(shuffled_nodes.begin(),shuffled_nodes.end(),r);
 
	
 
}
 

	
 
void Mesh::XMLReadWalls(xmlNode *root, vector<Wall *> *tmp_walls) {
 
	
 
  xmlNode *cur = root;
 
  cur = cur->xmlChildrenNode;
 
	
 
  for (list<Wall *>::iterator i=walls.begin();
 
       i!=walls.end();
 
       i++) {
 
    delete *i;
 
  }
 
	
 
  walls.clear();
 
  Wall::nwalls = 0;
 
  tmp_walls->clear();
 
  //Node::nnodes=0;
 
	
 
	
 
  QLocale standardlocale(QLocale::C);
 
  bool ok;
 

	
 
  while (cur!=NULL) {
 
		
 
    vector<int> tmp_nodes;
 
    while(cur!=NULL) {
 
      if ((!xmlStrcmp(cur->name, (const xmlChar *)"wall"))) {
 
				
 
	xmlChar *nc = xmlGetProp(cur, BAD_CAST "c1");
 
				
 
	if (nc==0) {
 
	  unique_warning("Token \"c1\" not found in xmlwrite.cpp at or around line no. 777");
 
	}
 
	int c1 = atoi( (char *)nc);
 
	xmlFree(nc);
 
				
 
	nc = xmlGetProp(cur, BAD_CAST "c2");
 
				
 
	if (	nc==0) {
 
	  unique_warning("Token \"c2\" not found in xmlwrite.cpp at or around line no. 785");
 
	}
 
	int c2 = atoi( (char *)nc);
 
	xmlFree(nc);
 
				
 
	nc = xmlGetProp(cur, BAD_CAST "n1");
 
				
 
	if (	nc==0) {
 
	  unique_warning("Token \"n1\" not found in xmlwrite.cpp at or around line no. 793");
 
	}
 
	int n1 = atoi( (char *)nc);
 
	xmlFree(nc);
 
				
 
	nc = xmlGetProp(cur, BAD_CAST "n2");
 
				
 
	if (	nc==0) {
 
	  unique_warning("Token \"n2\" not found in xmlwrite.cpp at or around line no. 801");
 
	}
 
	int n2 = atoi( (char *)nc);
 
	xmlFree(nc);
 
				
 
	nc = xmlGetProp(cur, BAD_CAST "length");
 
				
 
	if (	nc==0) {
 
	  unique_warning("Token \"length\" not found in xmlwrite.cpp at or around line no. 809");
 
	}
 
	//double length = strtod( (char *)nc, 0);
 

	
 
	double length = standardlocale.toDouble((const char *)nc, &ok);
 
	if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(const char *)nc);
 

	
 
	xmlFree(nc);
 
				
 
				
 
	nc = xmlGetProp(cur, BAD_CAST "viz_flux");
 
				
 
	double viz_flux = 0.0;
 
	if (nc!=0) {
 
	  //viz_flux = strtod( (char *)nc, 0);
 

	
 
	  viz_flux = standardlocale.toDouble((const char *)nc, &ok);
 
	  if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(const char *)nc);
 
	}
 
	xmlFree(nc);
 
				
 
	Wall::WallType wall_type;
 
	{
 
	  xmlChar *v_str = xmlGetProp(cur, BAD_CAST "wall_type");
 
					
 
	  if (v_str != 0) {
 
						
 
	    if (!xmlStrcmp(v_str, (const xmlChar *)"aux_source")) {
 
	      wall_type = Wall::AuxSource;
 
	    } else {
 
	      if (!xmlStrcmp(v_str, (const xmlChar *)"aux_sink")) {
 
		wall_type = Wall::AuxSink;
 
	      } else {
 
		wall_type = Wall::Normal;
 
	      }
 
	    }
 
	    xmlFree(v_str);
 
						
 
	  } else {
 
	    wall_type = Wall::Normal;
 
@@ -1267,164 +1246,158 @@ void Mesh::XMLReadWalls(xmlNode *root, v
 
	Cell *cc1 = c1 != -1 ? cells[c1] : boundary_polygon;
 
	Cell *cc2 = c2 != -1 ? cells[c2] : boundary_polygon;
 
				
 
	Wall *w = new Wall( nodes[n1], nodes[n2], cc1, cc2);
 
	w->length = length;
 
	w->viz_flux = viz_flux;
 
	w->wall_type = wall_type;
 
	w->dead = dead;
 
	tmp_walls->push_back(w);
 
	walls.push_back(w);
 
				
 
	xmlNode *w_node = cur->xmlChildrenNode;
 
	while (w_node!=NULL) {
 
	  if ((!xmlStrcmp(w_node->name, (const xmlChar *)"transporters1"))) {
 
						
 
	    xmlNode *v_node = w_node->xmlChildrenNode;
 
	    int nv=0;
 
	    while (v_node!=NULL) {
 
							
 
	      if ((!xmlStrcmp(v_node->name, (const xmlChar *)"val"))) {
 
		if (nv>=Cell::NChem()) {
 
		  {
 
		    stringstream text;
 
		    text << "Exception in Mesh::XMLRead: Too many transporter values given for wall(s). Ignoring remaining values.";
 
		    //ThrowStringStream(text);
 

	
 
		    unique_warning(text.str().c_str());
 
		    break;
 
		  }
 
		}
 
		xmlChar *nc = xmlGetProp(v_node, (const xmlChar *) "v");
 
								
 
		if (nc==0) {
 
		  unique_warning("Token \"v\" not found in xmlwrite.cpp at or around line no. 835");
 
		}
 
		//double v = strtod( (char *)nc, 0 );
 

	
 
		double v = standardlocale.toDouble((const char *)nc, &ok);
 
		if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(const char *)nc);
 

	
 
		w->transporters1[nv++]=v;
 
		xmlFree(nc);
 
								
 
	      }
 
	      v_node = v_node->next; 
 
	    }
 
						
 
	  }
 
					
 
					
 
	  if ((!xmlStrcmp(w_node->name, (const xmlChar *)"transporters2"))) {
 
						
 
	    xmlNode *v_node = w_node->xmlChildrenNode;
 
	    int nv=0;
 
	    while (v_node!=NULL) {
 
	      if ((!xmlStrcmp(v_node->name, (const xmlChar *)"val"))) {
 
		if (nv>=Cell::NChem()) {
 
		  {
 
		    stringstream text;
 
		    text << "Exception in Mesh::XMLRead: Too many transporter values given for wall(s). Ignoring remaining values.";
 
		    unique_warning(text.str().c_str());
 
		    break;
 
		    // ThrowStringStream(text);
 

	
 
		  }
 
		}
 
								
 
		xmlChar *nc = xmlGetProp(v_node, (const xmlChar *) "v");
 
								
 
		if (nc==0) {
 
		  unique_warning("Token \"v\" not found in xmlwrite.cpp at or around line no. 861");
 
		}
 
		//double v = strtod( (char *)nc, 0 );
 

	
 
		double v = standardlocale.toDouble((const char *)nc, &ok);
 
		if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(const char *)nc);
 

	
 
		w->transporters2[nv++]=v;
 
		xmlFree(nc);
 
	      }
 
	      v_node = v_node->next; 
 
	    }
 
						
 
	  } 
 
					
 
	  if ((!xmlStrcmp(w_node->name, (const xmlChar *)"apoplast"))) {
 
						
 
	    xmlNode *v_node = w_node->xmlChildrenNode;
 
	    int nv=0;
 
	    while (v_node!=NULL) {
 
							
 
	      if ((!xmlStrcmp(v_node->name, (const xmlChar *)"val"))) {
 
		if (nv>=Cell::NChem()) {
 
		  {
 
		    stringstream text;
 
		    text << "Exception in Mesh::XMLRead: Too many transporter values given for wall(s). Ignoring remaining values.";
 
		    //ThrowStringStream(text);
 

	
 
		    unique_warning(text.str().c_str());
 
		    break;
 
		  }
 
		}
 
		xmlChar *nc = xmlGetProp(v_node, (const xmlChar *) "v");
 
								
 
		if (nc==0) {
 
		  unique_warning("Token \"v\" not found in xmlwrite.cpp at or around line no. 887");
 
		}
 
		//double v = strtod( (char *)nc, 0 );
 

	
 
		double v = standardlocale.toDouble((const char *)nc, &ok);
 
		if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(const char *)nc);
 

	
 
		w->apoplast[nv++]=v;
 
		xmlFree(nc);
 
	      }
 
	      v_node = v_node->next; 
 
	    }
 
						
 
	  }
 
	  w_node=w_node->next;
 
	}
 
				
 
      }
 
      cur = cur->next;
 
    }
 
		
 
  }
 
  //  CleanUpWalls();
 
}
 

	
 

	
 
void Mesh::XMLReadWallsToCells(xmlNode *root, vector<Wall *> *tmp_walls) {
 
	
 
	// Add the walls to the cells (do this after reading the walls; read walls after reading cells...)
 
	// 1. Read Nodes
 
	// 2. Read Cells
 
	// 3. Read Walls
 
	// 4. Read Walls into Cells
 
	
 
	xmlNode *cur = root->xmlChildrenNode;
 
	int ci=0; // cell index
 
	
 
	while (cur!=NULL) {
 
		
 
		//Cell *new_cell=0;
 
		
 
		if ((!xmlStrcmp(cur->name, (const xmlChar *)"cell")) ||
 
			(!xmlStrcmp(cur->name, (const xmlChar *)"boundary_polygon" ))) {
 
			
 
			vector<int> tmp_walls_ind;
 
			xmlNode *n = cur->xmlChildrenNode;
 
			
 
			while(n!=NULL) {
 
				
 
				if ((!xmlStrcmp(n->name, (const xmlChar *)"wall"))) {
 
					xmlChar *nc = xmlGetProp(n, BAD_CAST "w");
 
					
 
					if (nc==0) {
 
						unique_warning("Token \"w\" not found in xmlwrite.cpp at or around line no. 931");
 
					}
 
					tmp_walls_ind.push_back(atoi( (char *)nc));
 
					xmlFree(nc);
 
				}
 
				n = n->next;
 
			}
 
			
 
			if (!xmlStrcmp(cur->name, (const xmlChar *)"boundary_polygon")) {
 
				
 
				int nwalls = tmp_walls_ind.size();
 
				for (int i=0;i<nwalls;i++) {
 
@@ -1563,86 +1536,79 @@ void Mesh::XMLReadCells(xmlNode *root) {
 
void Mesh::XMLRead(const char *docname, xmlNode **settings, bool geometry, bool pars, bool simtime) {
 
	
 
	xmlDocPtr doc = xmlParseFile(docname);
 
	if (doc == NULL ) {
 
		throw("Document not parsed successfully.");
 
		return;
 
	}
 
	
 
	xmlNodePtr cur = xmlDocGetRootElement(doc);
 
	
 
	if (cur == NULL) {
 
		throw("Document is empty");
 
		xmlFreeDoc(doc);
 
		return;
 
	}
 
	
 
	if (xmlStrcmp(cur->name, (const xmlChar *) "leaf")) {
 
		throw("XML file of the wrong type, it is not a leaf.");
 
		xmlFreeDoc(doc);
 
		return;
 
	}
 
	
 
	/*Get the root element node */
 
	xmlNode *root_element = xmlDocGetRootElement(doc);
 
	
 
	//XMLParseTree(root_element);
 

	
 
	if (geometry) XMLReadGeometry(root_element);
 
	if (pars) XMLReadPars(root_element);
 
	if (simtime) XMLReadSimtime(root_element);
 
	//print_element_names(root_element);
 
	
 
	// If pointer settings defined, return a copy of the settings tree
 
	if (settings) {
 
		xmlNode *cur = root_element->xmlChildrenNode;
 
		// if settings field is not found, *settings will be returned 0.
 
		*settings = 0;
 
		while (cur!=NULL) {
 
			if ((!xmlStrcmp(cur->name, (const xmlChar *)"settings"))){
 
				*settings = xmlCopyNode(cur,1);
 
			}
 
			cur=cur->next;
 
		}
 
	}
 
	xmlFreeDoc(doc);
 
	
 
	/*
 
	 *Free the global variables that may
 
	 *have been allocated by the parser.
 
	 */
 
	xmlCleanupParser();
 
	
 
	// We're doing this so we can manually delete walls with by adding the 'delete="true"' property
 
	CleanUpCellNodeLists();
 
	
 
}
 

	
 

	
 
/*  int Mesh::XMLReadWall(xmlNode *cur)  {
 
  
 

	
 
    return w;
 
    }*/
 
void Parameter::XMLRead(xmlNode *root) {
 
	
 
	xmlNode *cur = root->xmlChildrenNode;
 
	while (cur!=NULL) {
 
		if ((!xmlStrcmp(cur->name, (const xmlChar *)"parameter"))){
 
			xmlNode *par_node = cur->xmlChildrenNode;
 
			while (par_node!=NULL) {
 
				{
 
					if (!xmlStrcmp(par_node->name, (const xmlChar *)"par")) {
 
						xmlChar *namec = xmlGetProp(par_node, BAD_CAST "name");
 
						xmlChar *valc = xmlGetProp(par_node, BAD_CAST "val");
 
						if (valc) {
 
							AssignValToPar((const char*)namec,(const char*)valc);
 
						} else {
 
							/* Probably a valarray */
 
							xmlNode *sub_par_node = par_node->xmlChildrenNode;
 
							vector<double> valarray; 
 
							while (sub_par_node != NULL) {
 
								if (!xmlStrcmp(sub_par_node->name, (const xmlChar *)"valarray")) {
 
									valarray = XMLIO::XMLReadValArray(sub_par_node);
 
								}
 
								sub_par_node = sub_par_node->next;
 
							}
 
							AssignValArrayToPar((const char*)namec, valarray);
0 comments (0 inline, 0 general)