Changeset - 137d9d3a313a
[Not reviewed]
default
0 19 0
Michael Guravage - 15 years ago 2010-06-15 13:44:36
michael.guravage@cwi.nl
Removed most compilation warnings; see ChangeLogs for details.

--
user: Michael Guravage <michael.guravage@cwi.nl>
branch 'default'

changed .hgignore
changed src/ChangeLog
changed src/VirtualLeaf.cpp
changed src/apoplastitem.cpp
changed src/build_models/ChangeLog
changed src/build_models/auxingrowthplugin.cpp
changed src/build_models/meinhardtplugin.cpp
changed src/build_models/testplugin.cpp
changed src/canvas.cpp
changed src/cell.cpp
changed src/cellbase.h
changed src/forwardeuler.cpp
changed src/mainbase.h
changed src/mesh.cpp
changed src/nodeitem.cpp
changed src/output.cpp
changed src/qcanvasarrow.h
changed src/simitembase.cpp
changed src/xmlwrite.cpp
19 files changed with 103 insertions and 35 deletions:
0 comments (0 inline, 0 general)
.hgignore
Show inline comments
 
# use glob syntax.
 
syntax: glob
 

	
 
*~
 
*.a
 
*.exe
 
*.cache
 
*.Debug
 
*.o
 
*.orig
 
*.out
 
*.Release
 
*.so
 
*.vars
 
*Makefile.*
 
*make.out
 
*moc_*.cpp
 
src/default.par
 
bin*
 
TAGS
 
BROWSE
 

	
 
# switch to regexp syntax.
 
syntax: regexp
 

	
 
# finis
src/ChangeLog
Show inline comments
 
2010-06-15    <guravage@caterpie.sen.cwi.nl>
 

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

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

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

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

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

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

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

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

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

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

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

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

	
 

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

	
 

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

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

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

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

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

	
 
	* Makefile: Added top-level Makefile
 

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

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

	
src/VirtualLeaf.cpp
Show inline comments
 
/*
 
 *
 
 *  This file is part of the Virtual Leaf.
 
 *
 
 *  The Virtual Leaf is free software: you can redistribute it and/or modify
 
 *  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 <fstream>
 
#include <sstream>
 
#include <cstring>
 
#include <functional> 
 
#include <getopt.h>
 
#include <cerrno>
 
#include "mesh.h"
 
#include "parameter.h"
 
#include "random.h"
 
#include "pi.h"
 
#include "cellitem.h"
 
#include "canvas.h"
 
#include "cell.h"
 
#include "output.h"
 
#include <qwidget.h>
 
#include <q3process.h>
 
#include <qapplication.h>
 
#include <QDesktopWidget>
 
#include <QGraphicsScene>
 
#include <QMessageBox>
 
//Added by qt3to4:
 
#include <QMouseEvent>
 

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

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

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

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

	
 
extern Parameter par;
 

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

	
 

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

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

	
 

	
 
class EdgeSource {
 
	
 
public:
 
  void operator() (Cell &c) {
 
		
 
    if (c.AtBoundaryP()) {
 
      cerr << "Cell " << c.Index() << " is a source cell.\n";
 
      c.SetSource(0,par.source);
 
    } else {
 
      cerr << "Cell " << c.Index() << " is _not_ a source cell.\n";
 
    }
 
  }
 
};
 

	
 

	
 

	
 
class CellInfo {
 
public:
 
  void operator() (Cell &c,std::ostream &os) const {
 
    os << "Cell " << c.index << " says: " << endl;
 
    os << "c.nodes.size() = " << c.nodes.size() << endl;
 
    for (list<Node *>::iterator i=c.nodes.begin();
 
	 i!=c.nodes.end();
 
	 i++) {
 
      cerr << (*i)->Index() << " ";
 
    }
 
    cerr << endl;
 
  }
 
};
 

	
 
double PINSum(Cell &c) {
 
  return c.Chemical(1) + c.SumTransporters(1);// + c.ReduceCellAndWalls<double>( complex_PijAj );
 
}
 

	
 

	
 
class DrawCell {
 
public:
 
  void operator() (Cell &c,QGraphicsScene &canvas, MainBase &m) const {
 
    if (m.ShowBorderCellsP() || c.Boundary()==Cell::None) {
 
      if (!m.ShowBoundaryOnlyP() && !m.HideCellsP()) 
 
      if (!m.ShowBoundaryOnlyP() && !m.HideCellsP()) {
 
	if (m.ShowToolTipsP()) {
 
	  QString info_string=QString("Cell %1, chemicals: ( %2, %3, %4, %5, %6)\n %7 of PIN1 at walls.\n Area is %8\n PIN sum is %9\n Circumference is %10\n Boundary type is %11").arg(c.Index()).arg(c.Chemical(0)).arg(c.Chemical(1)).arg(c.Chemical(2)).arg(c.Chemical(3)).arg(c.Chemical(4)).arg(c.SumTransporters(1)).arg(c.Area()).arg(PINSum(c)).arg(c.Circumference()).arg(c.BoundaryStr());
 
					
 
	  info_string += "\n" + c.printednodelist();
 
	  c.Draw(&canvas, info_string);
 
	} else {
 
	  c.Draw(&canvas);
 
	}
 
      if (m.ShowCentersP())
 
      }
 
      if (m.ShowCentersP()){
 
	c.DrawCenter(&canvas);
 
      if (m.ShowFluxesP())
 
      }
 
      if (m.ShowFluxesP()){
 
	c.DrawFluxes(&canvas, par.arrowsize);
 
      }
 
    }
 
  }
 
};
 

	
 
Mesh mesh;
 
bool batch=false;
 

	
 
void MainBase::Plot(int resize_stride) {
 
	
 
  clear();
 
	
 
  static int count=0;
 
  if (resize_stride) {
 
    if ( !((++count)%resize_stride) ) {
 
      FitLeafToCanvas();
 
    }
 
  }
 
  mesh.LoopCells(DrawCell(),canvas,*this);
 
	
 
  if (ShowNodeNumbersP()) 
 
    mesh.LoopNodes( bind2nd (mem_fun_ref ( &Node::DrawIndex), &canvas ) ) ;
 
  if (ShowCellNumbersP()) 
 
    mesh.LoopCells( bind2nd (mem_fun_ref ( &Cell::DrawIndex), &canvas ) ) ;
 
	
 
  if (ShowCellAxesP()) 
 
    mesh.LoopCells( bind2nd (mem_fun_ref ( &Cell::DrawAxis), &canvas ) );
 
	
 
  if (ShowCellStrainP()) 
 
    mesh.LoopCells( bind2nd (mem_fun_ref ( &Cell::DrawStrain), &canvas ) );
 
	
 
  if (ShowWallsP())
 
    mesh.LoopWalls( bind2nd( mem_fun_ref( &Wall::Draw ), &canvas ) );
 
	
 
  if (ShowApoplastsP()) 
 
    mesh.LoopWalls( bind2nd( mem_fun_ref( &Wall::DrawApoplast ), &canvas ) );
 
 
 
  if (ShowMeshP()) 
 
    mesh.DrawNodes(&canvas);
 
	
 
  if (ShowBoundaryOnlyP()) 
 
    mesh.DrawBoundary(&canvas);
 

	
 
  if ( ( batch || MovieFramesP() )) {
 
		
 
    static int frame = 0;
 
    // frame numbers are sequential for the most frequently written file type.
 
    // for the less frequently written file type they match the other type
 
    if (!(count%par.storage_stride) )  {
 
		
 
      stringstream fname;
 
      fname << par.datadir << "/leaf.";
 
      fname.fill('0');
 
      fname.width(6);
 
	
 
      /* 
 
	 fname << frame << ".pdf";
 
	 if (par.storage_stride <= par.xml_storage_stride) {
 
	 frame++;
 
	 }
 
			
 
	 // Write high-res JPG snapshot every plot step
 
	 Save(fname.str().c_str(), "PDF");
 
      */
 
			
 
      fname << frame << ".jpg";
 
      if (par.storage_stride <= par.xml_storage_stride) {
 
	frame++;
 
      }
 
			
 
      // Write high-res JPG snapshot every plot step
 
      Save(fname.str().c_str(), "JPEG",1024,768);
 
    }
 
	
 
    if (!(count%par.xml_storage_stride)) {
 
      stringstream fname;
 
      fname << par.datadir << "/leaf.";
 
      fname.fill('0');
 
      fname.width(6);
 
      fname << frame << ".xml";
 
	
 
      if (par.xml_storage_stride < par.storage_stride) {
 
	frame++;
 
      }
 
      // Write XML file every ten plot steps
 
      mesh.XMLSave(fname.str().c_str(), XMLSettingsTree());
 
    }
 
  }
 
}
 

	
 

	
 

	
 
INIT {
 
	
 
  //mesh.SetSimPlugin(plugin);
 
  if (leaffile) { 
 
    xmlNode *settings;
 
    mesh.XMLRead(leaffile, &settings);
 
		
 
    main_window->XMLReadSettings(settings);
 
    xmlFree(settings);
 
    main_window->UserMessage(QString("Ready. Time is %1").arg(mesh.getTimeHours().c_str()));
 
		
 
  } else {
 
    mesh.StandardInit();
 
  }
 
}
 

	
 
TIMESTEP {
 
	
 
  static int i=0;
 
  static int t=0;
 
  static int ncells;
 
	
 
  if (!batch) {
 
    UserMessage(QString("Time: %1").arg(mesh.getTimeHours().c_str()),0);
 
  }
 
			 
 
  ncells=mesh.NCells();
 
		
 
				
 
  double dh;
 
  		
 
  if(DynamicCellsP()) {
 
    dh = mesh.DisplaceNodes();
 
			
 
    // Only allow for node insertion, cell division and cell growth
 
    // if the system has equillibrized
 
    // i.e. cell wall tension equillibrization is much faster
 
    // than biological processes, including division, cell wall yielding
 
    // and cell expansion
 
    mesh.InsertNodes(); // (this amounts to cell wall yielding)
 
			
 
    if ( (-dh) < par.energy_threshold) {
 
				
 
      mesh.IncreaseCellCapacityIfNecessary();
 
      mesh.DoCellHouseKeeping();
 
      //mesh.LoopCurrentCells(mem_fun(&plugin->CellHouseKeeping)); // this includes cell division
 
				
 
      // Reaction diffusion	
 
      /*CelltoCellTransport *transport_f = &TestPlugin::CelltoCellTransport;
 
	CellReaction *cellreaction_f = new plugin->CellDynamics();
 
	WallReaction *wall_f = new WallDynamics();*/
 
				
 
      mesh.ReactDiffuse(par.rd_dt);
 
				
 
      t++;
 
				
 
      Plot(par.resize_stride);
 
		
 
      /*QVector< QPair<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();
 
  }
 
}
 
				
 

	
 
Parameter par;
 
				
 
int main(int argc,char **argv) {
 
					
 
  try {
 
						
 

	
 
    int c;
 

	
 
						
 
    char *leaffile=0;
 
    char *modelfile=0;
 
						
 
    while (1) {
 
							
 
      //int this_option_optind = optind ? optind : 1;
 
      int option_index = 0;
 
      static struct option long_options[] = {
 
	{"batch", no_argument, NULL, 'b'},
 
	{"leaffile", required_argument, NULL, 'l'},
 
	{"model", required_argument, NULL, 'm'} 
 
      };
 
		
 
      // short option 'p' creates trouble for non-commandline usage on MacOSX. Option -p changed to -P (capital)
 
      static char *short_options = "blm";
 
      c = getopt_long (argc, argv, "bl:m:",
 
		       long_options, &option_index);
 
      if (c == -1)
 
	break;
 
		
 
		
 
      if (c==0) {
 
	printf ("option %s", long_options[option_index].name);
 
	if (optarg)
 
	  printf (" with arg %s", optarg);
 
	printf ("\n");
 
			
 
	c = short_options[option_index];
 
      }
 
		
 
      switch (c) {
 
      case 'b':
 
	cerr << "Running in batch mode\n";
 
	batch=true;
 
	break;
 
				
 
      case 'l':
 
	leaffile=strdup(optarg);
 
	if (!leaffile) {
 
	  throw("Out of memory");
 
	}
 
	printf("Reading leaf state file '%s'\n", leaffile);
 
	break;
 

	
 
      case 'm':
 
	modelfile=strdup(optarg);
 
	if (!modelfile) {
 
	  throw("Out of memory");
 
	}
 
	break;
 
					
 
      case '?':
 
	break;
 
				
 
      default:
 
	printf ("?? getopt returned character code 0%o ??\n", c);
 
      }
 
    }
 
	  
 
	  
 
    if (optind < argc) {
 
      printf ("non-option ARGV-elements: ");
 
      while (optind < argc)
 
	printf ("%s ", argv[optind++]);
 
      printf ("\n");
 
    }
 

	
 
    bool useGUI = !batch;
 
    qInstallMsgHandler(vlMessageOutput); // custom message handler
 
    QApplication app(argc,argv,useGUI);
 
						
 

	
 
    
 
    QPalette tooltippalette = QToolTip::palette();
 
    QColor transparentcolor = QColor(tooltippalette.brush(QPalette::Window).color());
 

	
 
    tooltippalette.setBrush (QPalette::Window, QBrush (transparentcolor) );
 
    QToolTip::setPalette( tooltippalette );
 

	
 
    QGraphicsScene canvas(0,0,8000,6000);
 

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

	
 
	((Main *)main_window)->show();
 
	((Main *)main_window)->resize( ((Main *)main_window)->sizeHint());
 
      } else {
 
        ((Main *)main_window)->showMaximized();
 
      }
 
    } 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
 
      return app.exec();
 
	  
 
						
 
  } catch (const char *message) {
src/apoplastitem.cpp
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.
 
 *
 
 */
 

	
 

	
 
#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){
 
		
 
	extern Parameter par;
 
	
 
	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;
 
	
 
	
 
	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
 
}
 

	
src/build_models/ChangeLog
Show inline comments
 
2010-06-15    <guravage@caterpie.sen.cwi.nl>
 

	
 

	
 
	* testplugin.cpp (CelltoCellTransport) Use NULL assignment merely to obviate compilation warnings.
 
	(WallDynamics): Ditto.
 
	(CellDynamics): Ditto.
 
	(OnDivide): Ditto.
 

	
 
	* meinhardtplugin.cpp (OnDivide): Use NULL assignment merely to obviate compilation warnings.
 
	* (WallDynamics): Ditto.
 

	
 
	* auxingrowthplugin.cpp (OnDivide): Use NULL assignment merely to obviate compilation warnings.
 

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

	
 
	* Makefile: Added top-level Makefile.
 

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

	
 
	* plugin_test.pro: Added -fPIC option to QMAKE_CXXFLAGS.
 
	* plugin_meinhardt.pro: ditto
 
	* plugin_auxingrowth.pro: ditto
 

	
 

	
src/build_models/auxingrowthplugin.cpp
Show inline comments
 
/*
 
 *
 
 *  This file is part of the Virtual Leaf.
 
 *
 
 *  The Virtual Leaf is free software: you can redistribute it and/or modify
 
 *  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 <QObject>
 
#include <QtGui>
 
#include "../simplugin.h"
 

	
 
#include "parameter.h"
 

	
 
#include "wallbase.h"
 
#include "cellbase.h"
 
#include "auxingrowthplugin.h"
 

	
 
#include "far_mem_5.h"
 

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

	
 
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];
 
			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];
 
			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
src/build_models/meinhardtplugin.cpp
Show inline comments
 
/*
 
 *
 
 *  This file is part of the Virtual Leaf.
 
 *
 
 *  The Virtual Leaf is free software: you can redistribute it and/or modify
 
 *  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 <QObject>
 
#include <QtGui>
 
#include "../simplugin.h"
 

	
 
#include "parameter.h"
 
#include "warning.h"
 
#include "wallbase.h"
 
#include "cellbase.h"
 
#include "meinhardtplugin.h"
 

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

	
 
bool batch = false;
 

	
 
// To be executed after cell division
 
void MeinhardtPlugin::OnDivide(ParentInfo *parent_info, CellBase *daughter1, CellBase *daughter2) {
 
	
 
  parent_info = NULL;
 
  daughter1 = daughter2 = NULL;
 
}
 

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

	
 
	if (fpclassify(c->Chemical(0))==FP_NAN) {
 
		// somehow the function isnan doesn't work properly on my system... SuSE Linux
 
		// 10.0 64-bits (isnan seems not be implemented using fpclassify).
 
		MyWarning::warning("Whoops! Numerical instability!!");
 
		color->setNamedColor("red");
 
	} else {
 
		double range_min = 0.;//, range_max = 1.;
 
		if (c->Chemical(0)<range_min) {
 
			MyWarning::warning("Whoops! Numerical instability!!");
 
			color->setNamedColor("blue");
 
		} else {
 
			color->setRgb(c->Chemical(1)/(1+c->Chemical(1)) * 255.,(c->Chemical(0)/(1+c->Chemical(0)) * 255.),(c->Chemical(3)/(1+c->Chemical(3)) *255.) );
 
		}
 
		
 
	}
 
}
 

	
 

	
 

	
 
void MeinhardtPlugin::CellHouseKeeping(CellBase *c) {
 
	
 
	if (c->Area() > par->rel_cell_div_threshold * c->BaseArea() ) {
 
		c->Divide();
 
	}
 
	
 
    // cell expansion is inhibited by substrate (chem 3)
 
	if (!par->constituous_expansion_limit || c->NCells()<par->constituous_expansion_limit) {
 
		c->EnlargeTargetArea(par->cell_expansion_rate );
 
	} else {
 
		if (c->Chemical(0)<0.5) {
 
			double tmp;
 
			c->EnlargeTargetArea((tmp=(1.-par->vessel_inh_level*c->Chemical(3))*par->cell_expansion_rate /* + c->Chemical(4)*/)<0?0:tmp); 
 
		} else {
 
			c->EnlargeTargetArea(par->vessel_expansion_rate);
 
		}
 
	} 
 
    
 
}
 

	
 
void MeinhardtPlugin::CelltoCellTransport(Wall *w, double *dchem_c1, double *dchem_c2) {
 
	
 
	// No flux boundaries for all chemicals, except activator: boundary is sink
 
  if (w->C1()->BoundaryPolP() || w->C2()->BoundaryPolP()) {
 
		
 
		if (w->C1()->BoundaryPolP()) {
 
			dchem_c2[1] -=  w->Length() * ( par->D[1] ) * ( w->C2()->Chemical(1) );
 
			} else {
 
			dchem_c1[1] -=  w->Length() * ( par->D[1] ) * ( w->C1()->Chemical(1) );
 
			} 
 
		return;
 
		}
 
	
 

	
 
    // 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.cpp
Show inline comments
 
/*
 
 *
 
 *  This file is part of the Virtual Leaf.
 
 *
 
 *  The Virtual Leaf is free software: you can redistribute it and/or modify
 
 *  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 <QObject>
 
#include <QtGui>
 

	
 
#include "simplugin.h"
 

	
 
#include "parameter.h"
 

	
 
#include "wallbase.h"
 
#include "cellbase.h"
 
#include "testplugin.h"
 

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

	
 
bool batch = false;
 

	
 
// To be executed after cell division
 
void TestPlugin::OnDivide(ParentInfo *parent_info, CellBase *daughter1, CellBase *daughter2) {
 
	
 
  parent_info = NULL;
 
  daughter1 = daughter2 = NULL;
 
}
 

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

	
 
	static QStringList colors;
 
	if (colors.size()==0) {
 
		colors << "red" << "green" << "blue";
 
	}
 
	color->setNamedColor(colors[c->Index()%colors.size()]);
 
}
 

	
 

	
 

	
 
void TestPlugin::CellHouseKeeping(CellBase *c) {
 
	
 
	c->EnlargeTargetArea(par->cell_expansion_rate);
 
	if (c->Area() > par->rel_cell_div_threshold * c->BaseArea() ) {
 
		c->Divide();
 
	}
 
}
 

	
 
void TestPlugin::CelltoCellTransport(Wall *w, double *dchem_c1, double *dchem_c2) {}
 
void TestPlugin::WallDynamics(Wall *w, double *dw1, double *dw2) {}
 
void TestPlugin::CellDynamics(CellBase *c, double *dchem) { }
 
void TestPlugin::CelltoCellTransport(Wall *w, double *dchem_c1, double *dchem_c2) {
 
  w = NULL;
 
  dchem_c1 = dchem_c2 = NULL;
 
}
 

	
 
void TestPlugin::WallDynamics(Wall *w, double *dw1, double *dw2) {
 
  w = NULL;
 
  dw1 = dw2 = NULL;
 
}
 

	
 
void TestPlugin::CellDynamics(CellBase *c, double *dchem) {
 
  c = NULL;
 
  dchem=NULL;
 
}
 

	
 
Q_EXPORT_PLUGIN2(testplugin, TestPlugin)
src/canvas.cpp
Show inline comments
 
/*
 
 *
 
 *  This file is part of the Virtual Leaf.
 
 *
 
 *  The Virtual Leaf is free software: you can redistribute it and/or modify
 
 *  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 <QDebug>
 

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

	
 
#include <set>
 

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

	
 
#include <algorithm>
 

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

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

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

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

	
 
static QColor dark_red("darkRed");
 

	
 

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

	
 
FigureEditor::FigureEditor(
 
			   QGraphicsScene& c, Mesh &m, QWidget* parent,
 
			   const char* name, Qt::WindowFlags f) :
 
  QGraphicsView(&c,parent), mesh(m)
 
{
 
  name = NULL; // use these two assignments merely to obviate compile time warnings
 
  f = Qt::Widget;
 

	
 
  intersection_line = 0;
 
  //angle_line = 0;
 
  setInteractive(true);
 
  moving = 0;  
 
  rotation_mode = false;
 
}
 

	
 

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

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

	
 

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

	
 
void FigureEditor::Save(const char *fname, const char *format, int sizex, int sizey) {
 
  
 
    QImage *image = new QImage(sizex, sizey, QImage::Format_RGB32);
 
    image->fill(QColor(Qt::white).rgb());
 
    QPainter *painter=new QPainter(image);
 
    
 
    render(painter);
 
    
 
    image->save(QString(fname),format);
 
    delete painter;
 
    delete image;
 
}
 

	
 
//void FigureEditor::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());
 

	
 
  NodeItem *item;
 

	
 
#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 QDEBUG
 
      #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
src/cell.cpp
Show inline comments
 
@@ -1624,385 +1624,385 @@ void BoundaryPolygon::Draw(QGraphicsScen
 

	
 
void Cell::Flux(double *flux, double *D)  {
 
	
 
	
 
	// loop over cell edges
 
	
 
	for (int c=0;c<NChem();c++) flux[c]=0.;
 
	
 
	for (list<Wall *>::iterator i=walls.begin();
 
		 i!=walls.end();
 
		 i++) {
 
		
 
		
 
		// leaf cannot take up chemicals from environment ("no flux boundary")
 
		if ((*i)->c2->BoundaryPolP()) continue;
 
		
 
		
 
		// flux depends on edge length and concentration difference
 
		for (int c=0;c<NChem();c++) {
 
			double phi = (*i)->length * ( D[c] ) * ( ((Cell *)(*i)->c2)->chem[c] - chem[c] );
 
			
 
			#ifdef QDEBUG
 
			if ((*i)->c1!=this) {
 
			  qDebug() << "Warning, bad cells boundary: " << (*i)->c1->Index() << ", " << index << endl;
 
			}
 
			#endif
 
			
 
			flux[c] += phi;
 
		}    
 
	}
 
	
 
}
 

	
 

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

	
 
#include "canvas.h"
 

	
 
void Cell::Draw(QGraphicsScene *c, QString tooltip) {
 
	
 
	// Draw the cell on a QCanvas object
 
	
 
	if (DeadP()) { 
 
	        #ifdef QDEBUG
 
	  qDebug() << "Cell " << index << " not drawn, because dead." << endl;
 
		#endif
 
		return;
 
	}
 
	
 
	CellItem* p = new CellItem(this, c);
 
	
 
	QPolygonF pa(nodes.size());
 
	int cc=0;
 
	
 
	for (list<Node *>::const_iterator n=nodes.begin();
 
		 n!=nodes.end();
 
		 n++) {
 
		Node *i=*n;
 
		
 
		pa[cc++] = QPoint((int)((offset[0]+i->x)*factor),
 
						  (int)((offset[1]+i->y)*factor) );
 
	}
 
	
 
	
 
	QColor cell_color;
 
	
 
	m->plugin->SetCellColor(this,&cell_color);
 
	
 
	p->setPolygon(pa);
 
	p->setPen(par.outlinewidth>=0?QPen( QColor(par.cell_outline_color),par.outlinewidth):QPen(Qt::NoPen));
 
	p->setBrush( cell_color );
 
	p->setZValue(1);
 
	
 
	if (!tooltip.isEmpty())
 
		p->setToolTip(tooltip);
 
	
 
	p->show();
 
	
 
}
 

	
 

	
 
void Cell::DrawCenter(QGraphicsScene *c) const {
 
  // Maginfication derived similarly to that in nodeitem.cpp
 
  // Why not use Cell::Magnification()?
 
  const double mag = par.node_mag;
 
	
 
	// construct an ellipse
 
  QGraphicsEllipseItem *disk = new QGraphicsEllipseItem ( -1*mag, -1*mag, 2*mag, 2*mag, 0, c );
 
	disk->setBrush( QColor("forest green") );
 
	disk->setZValue(5);
 
	disk->show();
 
	Vector centroid=Centroid();
 
	disk -> setPos((offset[0]+centroid.x)*factor,(offset[1]+centroid.y)*factor);
 
}
 

	
 
void Cell::DrawNodes(QGraphicsScene *c) const {
 
	
 
	for (list<Node *>::const_iterator n=nodes.begin();
 
		 n!=nodes.end();
 
		 n++) {
 
		Node *i=*n;
 
		
 
		//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 {
 
	></i>
 
  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();
 
	
 
}
 

	
 

	
 
void Cell::DrawWalls(QGraphicsScene *c) const {
 
	
 
	for_each(walls.begin(), walls.end(), bind2nd ( mem_fun ( &Wall::Draw ) , c ) );
 
	
 
	// to see the cells connected the each wall (for debugging), uncomment the following
 
	//for_each(walls.begin(), walls.end(), bind2nd ( mem_fun ( &Wall::ShowStructure ), c ) );
 
}
 

	
 

	
 
void Cell::DrawValence(QGraphicsScene *c) const {
 
	
 
	DrawText(c, QString("%1").arg(walls.size()) );
 
	
 
}
 

	
 
#endif
 

	
 
/*! \brief Recalculate the lengths of the cell's Walls.
 
 
 
 Call this function after the Monte Carlo updates, and before doing the reaction-diffusion iterations.
 
 
 
 */
 
void Cell::SetWallLengths(void) {
 
	
 
	for (list<Wall *>::iterator de=walls.begin();
 
		 de!=walls.end();
 
		 de++) {
 
		
 
		// Step 1: find the path of nodes leading along the Wall.
 
		// A Wall often represents a curved cell wall: we want the total
 
		// length _along_ the wall here...
 
		
 
		
 
		// Locate first and second nodes of the edge in list of nodes
 
		list<Node *>::const_iterator first_node_edge = find(nodes.begin(), nodes.end(), (*de)->n1);
 
		list<Node *>::const_iterator second_node_edge_plus_1 = ++find(nodes.begin(), nodes.end(), (*de)->n2);
 
		
 
		double sum_length = 0.;
 
		
 
		// Now, walk to the second node of the edge in the list of nodes
 
		for (list<Node *>::const_iterator n=++first_node_edge;
 
			 n!=second_node_edge_plus_1;
 
			 ++n ) {
 
			
 
			if (n==nodes.end()) n=nodes.begin(); /* wrap around */ 
 
			
 
			
 
			list<Node *>::const_iterator prev_n = n; 
 
			if (prev_n==nodes.begin()) prev_n=nodes.end();
 
			--prev_n;
 
			
 
			
 
			// Note that Node derives from a Vector, so we can do vector calculus as defined in vector.h 
 
			sum_length += (*(*prev_n) - *(*n)).Norm(); 
 
			
 
			//cerr << "Node " << *prev_n << " to " << *n << ", cumulative length = " << sum_length << endl;
 
		}
 
		
 
		// We got the total length of the Wall now, store it:
 
		(*de)->length = sum_length;
 
		
 
		//cerr << endl;
 
		// goto next de
 
	}
 
}
 

	
 

	
 
//! Add Wall w to the list of Walls
 
void Cell::AddWall( Wall *w ) {
 
	
 
	// if necessary, we could try later inserting it at the correct position
 
        #ifdef QDEBUG
 
	if (w->c1 == w->c2 ){
 
	  qDebug() << "Wall between identical cells: " << w->c1->Index()<< endl;
 
	}
 
	#endif
 

	
 
	// Add Wall to Cell's list
 
	walls.push_back( w );
 
	
 
	// Add wall to Mesh's list if it isn't there yet
 
	
 
	if (find (
 
			  m->walls.begin(), m->walls.end(),
 
			  w )
 
		== m->walls.end() ) {
 
		m->walls.push_back(w);
 
	}
 
	
 
}
 

	
 
//! Remove Wall w from the list of Walls
 
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 )
 
				 );
 
	
 
}
src/cellbase.h
Show inline comments
 
@@ -301,202 +301,203 @@ class CellBase :  public QObject, public
 
      for (list<Wall *>::const_iterator w=walls.begin();
 
	   w!=walls.end();
 
	   w++) {
 
	sum +=  (*w)->Length() * ( (*w)->c1!=this ? (*w)->c1->Chemical(chem) : (*w)->c2->Chemical(chem) );
 
      }
 
      return sum;
 
    }
 

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

	
 
    //! The same, but now for the walls
 
    template<class P, class Op> P ReduceWalls(Op f, P sum) {
 
      for (list<Wall *>::const_iterator w=walls.begin();
 
	   w!=walls.end();
 
	   w++) {
 
	sum += f( **w ); 
 
      }
 
      return sum;
 
    }
 
	
 
	
 
    
 
    
 
    //! The same, but now for the walls AND neighbors
 
    template<class P, class Op> P ReduceCellAndWalls(Op f) {
 
      P sum = 0;
 
      for (list<Wall *>::const_iterator w=walls.begin();
 
	   w!=walls.end();
 
	   w++) {
 
	sum += ((*w)->c1 == this) ? 
 
	  f( ((*w)->c1), ((*w)->c2), *w ) :  
 
	  f( ((*w)->c2), ((*w)->c1), *w );
 
      }
 
      return sum;
 
    }
 
    
 
	/* 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();
 
      
 
      }
 
      
 
      return sum;
 
    }
 
    
 
	
 
    
 
    double SumLengthTransportersChemical(int trch, int ch) {
 
      double sum=0.;
 
      for (list<Wall *>::const_iterator w=walls.begin();
 
	   w!=walls.end();
 
	   w++) {
 
	sum += (*w)->getTransporter(this, trch) * ( (*w)->c1!=this ? (*w)->c1->Chemical(ch) : (*w)->c2->Chemical(ch) );
 
	
 
      }
 
      
 
      return sum;
 
    }
 
	inline int CellType(void) const { return cell_type; } 
 
	inline void SetCellType(int ct) { cell_type = ct; }
 

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

	
 
	static inline CellsStaticDatamembers *GetStaticDataMemberPointer(void) { return static_data_members; }
 
	
 
protected:
 
	// (define a list of Node* iterators)
 
	typedef list < list<Node *>::iterator > ItList;
 

	
 
    int index;
 

	
 
	inline void SetChemToNewchem(void) {
 
		for (int c=0;c<CellBase::NChem();c++) {
 
			chem[c]=new_chem[c];
 
		}
 
    }
 
    inline void SetNewChemToChem(void) {
 
		for (int c=0;c<CellBase::NChem();c++) {
 
			new_chem[c]=chem[c];
 
		}
 
    }
 
	inline double NewChem(int c) const { return new_chem[c]; }
 
	
 
 protected:
 
    list<Node *> nodes;
 
    void ConstructNeighborList(void);
 
	long wall_list_index (Wall *elem) const;
 

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

	
 
    list<Wall *> walls;
 
  
 
    double *chem;
 
    double *new_chem;
 
  
 
    boundary_type boundary;
 
    mutable double area;
 
    double target_area;
 
    double target_length;
 
    double lambda_celllength;
 

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

	
 
    bool fixed;
 
    bool pin_fixed;
 
    bool at_boundary; 
 
    bool dead; 
 
	bool flag_for_divide;
 
	
 
	Vector *division_axis;
 
	
 
	int cell_type;
 
	
 
    //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) {
 
	return w->getTransporter( here, 1)  *  w->getInfluxVector(here);
 
	  nb = NULL; // assignment merely to obviate compilation warning
 
	  return w->getTransporter( here, 1)  *  w->getInfluxVector(here);
 
}
 

	
 

	
 
#endif
 

	
 

	
 

	
 

	
 

	
src/forwardeuler.cpp
Show inline comments
 
/*
 
 *
 
 *  This file is part of the Virtual Leaf.
 
 *
 
 *  The Virtual Leaf is free software: you can redistribute it and/or modify
 
 *  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 <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. */
 
{
 
  static bool warning_issued = false;
 

	
 
  eps = hmin = 0.0; // use assignment merely to obviate compilation warning
 
  nbad = nok = NULL;
 

	
 
  if (!warning_issued) {
 
    cerr << "Using inaccurate method ForwardEuler\n";
 
    warning_issued=true;
 
    //MyWarning::warning("Using inaccurate method ForwardEuler");
 
  }
 
  // N.B. Not for serious use and not fully usage compatible with RungeKutta
 
  // simply for testing API of integrator.
 
  
 
  double *y,*dydx;
 
  y=new double[nvar];
 
  dydx=new double[nvar];
 
  double x=x1;
 
    
 
  for (int i=0;i<nvar;i++) y[i]=ystart[i];
 

	
 
  //if (kmax > 0) xsav=x-dxsav*2.0; //Assures storage of first step.
 

	
 
  dydx=new double[nvar];
 

	
 
  for (int nstp=0;nstp<Maxstp;nstp++) {
 
    
 
    derivs(x,y,dydx);
 
    
 
    if (kmax > 0 && kount < kmax-1) {
 
      xp[kount]=x; //Store intermediate results.
 
      for (int i=0;i<nvar;i++) yp[i][kount]=y[i];
 
      kount++;
 
      //xsav=x;
 
    }
 

	
 

	
 
    for (int i=0;i<nvar;i++) {
 
      y[i]=y[i] + h1 * dydx[i];
 
    }
 
      
 
    x = x + h1;
 

	
 
    if ((x-x2)*(x2-x1) >= 0.0) { //Are we done?
 
      goto done;
 
    }
 

	
 

	
 
  }
 

	
 
 done:
 
  for (int i=0;i<nvar;i++) ystart[i]=y[i];
 
  if (kmax) {
 
    xp[kount]=x; //Save final step.
 
    for (int i=0;i<nvar;i++) yp[i][kount]=y[i];
 
    
 
  }
 
  
 
  delete[] dydx;
 
  delete[] y;
 
  return; //Normal exit.
 

	
 
}
src/mainbase.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  This file is part of the Virtual Leaf.
 
 *
 
 *  The Virtual Leaf is free software: you can redistribute it and/or modify
 
 *  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 _MAINBASE_H_
 
#define _MAINBASE_H_
 

	
 
#include <QGraphicsScene>
 
#include <qpixmap.h>
 
#include <q3picture.h>
 
#include <qpainter.h>
 
#include <qwidget.h>
 
#include <iostream>
 
#include <QGraphicsItem>
 
#include <QPrinter>
 
#include "mesh.h"
 
#include "warning.h"
 

	
 
using namespace std;
 

	
 
/*! Implement these functions in your main application */
 
class MainBase  {
 

	
 
 public:
 
  MainBase(QGraphicsScene &c, Mesh &m) : mesh(m), canvas(c) {
 
    
 
    // Standard options for batch version
 
    showcentersp =  false;
 
    showmeshp =  false;
 
    showbordercellp =  false;
 
    shownodenumbersp =  false;
 
    showcellnumbersp =  false;
 
    showcellsaxesp = false;
 
    showcellstrainp =  false;
 
    movieframesp = true;
 
    showboundaryonlyp =  false;
 
    showwallsp =  false;
 
    showfluxesp = false;
 
    dynamicscellsp = true;
 
    showtooltipsp = false;
 
	hidecellsp = false;
 
  }
 
    virtual ~MainBase() {};
 
    
 
    virtual double TimeStep();
 
    virtual void Init(char *leaffile=0);
 
    
 
    virtual bool ShowCentersP(void) {return showcentersp;}
 
    virtual bool ShowMeshP(void) {return showmeshp; }
 
    virtual bool ShowBorderCellsP(void) {return showbordercellp; }
 
    virtual bool PausedP(void) {return false; }
 
    virtual bool ShowNodeNumbersP(void) {return shownodenumbersp; }
 
    virtual bool ShowCellNumbersP(void) {return showcellnumbersp;}
 
    virtual bool ShowCellAxesP(void) {return showcellsaxesp;}
 
    virtual bool ShowCellStrainP(void) {return showcellstrainp;}
 
    virtual bool MovieFramesP(void) {return movieframesp;}
 
    virtual bool ShowBoundaryOnlyP(void) {return showboundaryonlyp;}
 
    virtual bool ShowToolTipsP(void) {return showtooltipsp;}
 
    virtual bool ShowWallsP(void) {return showwallsp;}
 
	virtual bool ShowApoplastsP(void) { return showapoplastsp;}
 
    virtual bool ShowFluxesP(void) { return showfluxesp; }
 
    virtual bool DynamicCellsP(void) { return dynamicscellsp; }
 
    virtual void FitCanvasToWindow() {};
 
    virtual void FitLeafToCanvas() {};
 
	virtual bool HideCellsP(void) { return hidecellsp; }
 
    virtual void clear(void) {
 
      QList<QGraphicsItem *> list = canvas.items();
 
      QList<QGraphicsItem *>::Iterator it = list.begin();
 
      for (; it != list.end(); ++it) {
 
	if ( *it )
 
	  delete *it;
 
      }
 
    };
 
    virtual void XMLReadSettings(xmlNode *settings);
 
    virtual 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 showfluxesp;
 
    bool dynamicscellsp;
 
    bool showtooltipsp;
 
	bool hidecellsp;
 
};
 

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

	
 
#endif
src/mesh.cpp
Show inline comments
 
@@ -1469,385 +1469,385 @@ void Mesh::CutAwayBelowLine( Vector star
 
  #ifdef QDEBUG
 
  qDebug() << "Before CleanUpCellNodeLists" << endl;
 
  #endif
 
  TestIllegalWalls();
 
  
 
  CleanUpCellNodeLists();
 

	
 
}
 

	
 
void Mesh::CutAwaySAM(void) {
 

	
 
  for (vector<Cell *>::iterator i=cells.begin();
 
       i!=cells.end();
 
       i++) {
 
    
 
    if( (*i)->Boundary() == Cell::SAM ) {
 

	
 
	(*i)->Apoptose();
 
    }
 
  }
 

	
 
  TestIllegalWalls();
 
  
 
  CleanUpCellNodeLists();
 

	
 

	
 
}
 
void Mesh::TestIllegalWalls(void) {
 

	
 
  for (list<Wall *>::iterator w = walls.begin();
 
       w!=walls.end();
 
       w++) {
 
    if ((*w)->IllegalP() ) {
 
      #ifdef QDEBUG
 
      qDebug() << "Wall " << **w << " is illegal." << endl;
 
      #endif
 
    }
 
  }
 

	
 
}
 

	
 

	
 

	
 
class node_owners_eq : public unary_function<Node, bool> {
 
  int no;
 
public:
 
  
 
  explicit node_owners_eq(int nn) { no=nn; }
 

	
 
  bool operator() (const Node &n) const {
 
    if (n.CellsSize()==1) 
 
      return true;
 
    else 
 
      return false;
 
  }
 
  
 
};
 

	
 

	
 
void Mesh::RepairBoundaryPolygon(void) {
 
  
 
  // After serious manipulations (e.g. after cutting part off the
 
  // leaf) repair the boundary polygon. It assumes the cut line has
 
  // already been marked "boundary" and the original boundary marks
 
  // were not removed. 
 
  //
 
  // So, this function just puts boundary nodes into the boundary
 
  // polygon in the right order; it cannot detect boundaries from
 
  // scratch.
 
  
 
  Node *boundary_node=0, *next_boundary_node=0, *internal_node;
 
  set<int> original_boundary_nodes, repaired_boundary_nodes;
 
  vector<int> difference; // set difference result
 

	
 
  // Step 0: print out current boundary polygon
 
#ifdef QDEBUG
 
  qDebug() << endl << "Original Boundary Polygon node indices: ";
 
  foreach (Node* node, boundary_polygon->nodes) {
 
    qDebug() << node->Index() << " " ;
 
  }    
 
  qDebug() << endl << endl;
 
#endif
 

	
 
  // Step 1a: Create a set containing the current boundary polygon nodes' Indices.
 
  foreach (Node* node, boundary_polygon->nodes) {
 
    original_boundary_nodes.insert(node->Index());
 
  }
 

	
 
  // Step 1b: remove all nodes from boundary polygon
 
  boundary_polygon->nodes.clear();
 

	
 
  // Step 2: Remove all references to the boundary polygon from the Mesh's current list of nodes
 
  foreach (Node* node, nodes) {
 
    node->Unmark(); // remove marks, we need them to determine if we have closed the circle
 
    list<Neighbor>::iterator boundary_ref_pos;
 
    if ((boundary_ref_pos = find_if (node->owners.begin(), node->owners.end(), 
 
				     bind2nd(mem_fun_ref(&Neighbor::CellEquals), -1))) != node->owners.end()) {
 
      // i.e. if one of the node's owners is the boundary polygon 
 
      node->owners.erase(boundary_ref_pos); // remove the reference
 
    }
 
  }
 
  
 
  // Step 3: Search for the first boundary node.  We reconstruct the
 
  // boundary polygon by moving along the boundary nodes until we've
 
  // encircled the polygon. Since manually adding nodes may have
 
  // turned nodes previously along the boundary into internal nodes,
 
  // we search through all the node until we find first boundary node
 
  // and proceed from there. If findNextBoundaryNode() returns a node
 
  // other than the one passed to it, the original node is the first
 
  // boundary node.
 
  foreach (Node* node, nodes) {
 
    if ((findNextBoundaryNode(node))->index != node->index){
 
      next_boundary_node = node;
 
      break;
 
    }
 
  }
 

	
 
  // We have a problem if we arrive here without having found a boundary node.
 
  if (!next_boundary_node) throw("Cannot find a boundary node!.");
 

	
 
  // Reconstruct the list of boundary polygon nodes.
 
  do {
 
    boundary_node = next_boundary_node;
 
    boundary_node->Mark();
 
    boundary_polygon->nodes.push_back(boundary_node);
 
    next_boundary_node = findNextBoundaryNode(boundary_node);
 
  } while ( !next_boundary_node->Marked() );
 

	
 

	
 
  // Create a set containing the reconstructed boundary polygon nodes' Indices.
 
  for (list<Node *>::iterator it = boundary_polygon->nodes.begin(); it!=boundary_polygon->nodes.end(); ++it) {
 
    repaired_boundary_nodes.insert((*it)->Index());
 
  }
 

	
 
  // Calculate the difference between the original and repaired sets of boundary nodes
 
  // yielding the set of nodes that are no longer part of the boundary polygon.
 
  set_difference(original_boundary_nodes.begin(), original_boundary_nodes.end(),
 
                 repaired_boundary_nodes.begin(), repaired_boundary_nodes.end(), back_inserter(difference));
 

	
 
  // Tell each node in the difference that it's no longer part of the boundary polygon
 
  vector<Node *>::iterator internal_node_it;
 
  foreach (int i, difference){
 
    internal_node_it = find_if (nodes.begin(), nodes.end(), bind2nd(mem_fun(&Node::IndexEquals), i));
 
    internal_node = *internal_node_it; // dereference the itterator to get to the node pointer
 
    if (!internal_node) throw("Found a null Node pointer.");
 
    internal_node->UnsetBoundary();
 
  }
 

	
 
  boundary_polygon->ConstructConnections();
 
  for (list<Wall *>::iterator w=boundary_polygon->walls.begin();
 
       w!=boundary_polygon->walls.end();
 
       w++) {
 
    if ((*w)->DeadP()) {
 
      (*w)=0;
 
    }
 
  }
 
  boundary_polygon->walls.remove(0);
 
  boundary_polygon->ConstructNeighborList();
 
  
 
#ifdef QDEBUG
 
  qDebug() << "Repaired Boundary Polygon node indices: ";
 
  foreach (Node* node, boundary_polygon->nodes){
 
    qDebug() << node->Index() << " " ;
 
  }
 
  qDebug() << endl ;
 

	
 
  #ifdef _undefined_
 
  qDebug() << "NODES:" << endl;
 
  foreach(Node* node, nodes) {
 
    qDebug() << *node;
 
  }
 
  qDebug() << endl;
 

	
 
  qDebug() << "WALLS:" << endl;
 
  foreach(Wall* wall, walls) {
 
    qDebug() << *wall;
 
  }
 
  qDebug() << endl;
 

	
 
  qDebug() << "CELLS:" << endl;
 
  foreach(Cell* cell, cells) {
 
    qDebug() << *cell;
 
  }
 
  qDebug() << endl;
 
  #endif
 
#endif
 

	
 
}
 

	
 

	
 
Node* Mesh::findNextBoundaryNode(Node* boundary_node) {
 
  bool found_next_boundary_node = false;
 
  Node *next_boundary_node;
 
  Node *next_boundary_node = NULL;
 
  set<int> boundary_node_owners; // This is a list of the current boundary node's owners' Ids
 
  vector<int> neighborIds; // A list of the current boundary node's owners' 2nd neighbor Ids
 
  vector<set<int> *>  nodeOwners; // A vector of set pointers where each set contains the owner Ids of the nodes in the neighborIds list.
 
  vector<int> intersection; // set intersection result
 

	
 
  // The next boundary node is that which has only one owner in common with the current boundary node
 
  for (list<Neighbor>::iterator it=boundary_node->owners.begin(); it!=boundary_node->owners.end(); ++it) {
 
    if (it->cell->Index() != -1) boundary_node_owners.insert(it->cell->Index()); // Save each of the current boundary node's owners' Ids - except the boundary polygon 
 
    set<int> *owners = new set<int>; // create a set to hold a 2nd neighbor's owners' Ids
 
    nodeOwners.push_back(owners);
 
    neighborIds.push_back(it->nb2->Index());
 
    foreach(Neighbor neighbor, it->nb2->owners){
 
      if (neighbor.cell->Index() != -1) owners->insert(neighbor.cell->Index()); // Save second neighbors' owners' Ids - except the boundary polygon 
 
    }
 
  }
 
  vector<int>::iterator itt = neighborIds.begin();
 
  vector<set<int> *>::iterator it = nodeOwners.begin();
 

	
 
  #ifdef QDEBUG  
 
  qDebug() << "Boundary node: " <<  boundary_node->Index() << " is owned by the following cells: ";
 
  foreach (int i, boundary_node_owners){
 
    qDebug() << i << "  ";
 
  }
 
  qDebug() << endl;
 
  #endif
 

	
 
  for (; it < nodeOwners.end(); it++, itt++) {
 
    intersection.clear();
 
    set_intersection(boundary_node_owners.begin(), boundary_node_owners.end(), (*it)->begin(), (*it)->end(), back_inserter(intersection));
 

	
 
    #ifdef QDEBUG  
 
    qDebug() << "The intersection of the boundary node(" << boundary_node->Index() << ") owners and its 2nd neighbor(" <<  *itt << ") owners is: ";
 
    foreach (int i, intersection){
 
      qDebug() << i << "  ";
 
    }
 
    qDebug() << endl;
 
    #endif
 

	
 
    if (intersection.size() == 1){
 
      found_next_boundary_node = true;
 
      vector<Node *>::iterator next_boundary_node_it = find_if (nodes.begin(), nodes.end(), bind2nd(mem_fun(&Node::IndexEquals), *itt));
 
      next_boundary_node = *next_boundary_node_it; // defeference the itterator to get to the node pointer
 

	
 
      #ifdef QDEBUG  
 
      qDebug() << "The Current boundary node is: " << boundary_node->Index()
 
	       << ". The Next boundary node is: " << *itt << ((next_boundary_node->Marked()) ? " Marked" : " Unmarked") << endl << endl;
 
      #endif
 

	
 
      break;
 
    }
 
  }
 

	
 
  #ifdef QDEBUG  
 
  if (!found_next_boundary_node) {
 
    qDebug() << "OOPS! Didn't find the next boundrary node!" << endl;
 
  }
 
  #endif
 

	
 
  return next_boundary_node;
 
}
 

	
 

	
 
void Mesh::CleanUpWalls(void) {
 
  for (list<Wall *>::iterator w=walls.begin();
 
       w!=walls.end();
 
       w++) {
 

	
 
    if ((*w)->DeadP()) {
 
      delete *w;
 
      (*w)=0;      
 
    }
 
  }
 
  walls.remove(0);
 
}
 

	
 
void Mesh::Rotate(double angle, Vector center) {
 

	
 
  // Rotate the mesh over the angle "angle", relative to center point "center".
 

	
 
  Matrix rotmat;
 

	
 
  rotmat.Rot2D(angle);
 
  
 
  for (vector<Node *>::iterator n=nodes.begin();
 
       n!=nodes.end();
 
       n++) {
 

	
 
    (*n)->setPos ( rotmat * ( *(*n) - center ) + center );  
 
    
 
  }
 
}
 

	
 

	
 
void Mesh::PrintWallList( void ) {
 
  
 
   transform ( walls.begin(), walls.end(), ostream_iterator<Wall>(cerr, "\n"), deref_ptr<Wall> );
 

	
 
}
 

	
 
#include <QString>
 
//#include "forwardeuler.h"
 
#include "rungekutta.h"
 

	
 
class SolveMesh : public RungeKutta {
 
    
 
private:
 
  SolveMesh(void);
 
    
 
public:
 
	SolveMesh(Mesh *m_) {
 
    
 
		m = m_;
 
				
 
		kmax=0;
 
		kount=0;
 
		xp=0; yp=0; dxsav=0;
 
		
 
    
 
	}
 
  
 
protected:
 
  virtual void derivs(double x, double *y, double *dydx) {
 
      
 
    // set mesh with new values given by ODESolver
 
    // (we must do this, because only mesh knows the connections
 
    // between the variables)
 
    
 
    m->setValues(x,y);
 
    m->Derivatives(dydx);
 
    
 
    /*static int c=0;
 
       QString fname("derivs%1.dat");
 
       
 
       ofstream of(fname.arg(++c).ascii());
 
       
 
       for (int i=0;i<m->NEqs();i++) {
 
       of << x << " " << dxdy[i] << endl;
 
       }
 
       of.close();
 
    */
 
    
 
    //cerr << "Calculated derivatives at " << x << "\n";    
 
  }
 
  
 
private:
 
  Mesh *m;
 
  int kmax,kount;
 
  double *xp,**yp,dxsav;
 
  bool monitor_window;
 
};
 
  
 

	
 

	
 
void Mesh::ReactDiffuse(double delta_t) {
 
  
 
  // Set Lengths of Walls
 
  for_each ( walls.begin(), walls.end(), 
 
	     mem_fun( &Wall::SetLength ) );
 
  
 
  static SolveMesh *solver = new SolveMesh(this);
 
  
 
  int nok, nbad, nvar;
 
  double *ystart = getValues(&nvar);
 
  
 
  solver->odeint(ystart, nvar, getTime(), getTime() + delta_t, 
 
		 par.ode_accuracy, par.dt, 1e-10, &nok, &nbad);
 
  
 
  setTime(getTime()+delta_t);
 
  setValues(getTime(),ystart);
 
  
 
}
 

	
 

	
 
Vector Mesh::FirstConcMoment(int chem) {
 
  
 
  Vector moment;
 
  for (vector<Cell *>::const_iterator c=cells.begin();
 
       c!=cells.end();
 
       c++) {
 
    
 
    moment += (*c)->Chemical(chem) * (*c)->Centroid();
 
    
 
  }
 

	
 
  return moment / (double)cells.size();
 
}
 

	
 
/*! This member function deletes all walls connected to two dead cells from the mesh.
 
  It should be called before the Cells are actually removed.
 
  If the cell is connect to one dead cell only, that reference is substituted for a reference 
 
  to the boundary polygon.
 
*/
src/nodeitem.cpp
Show inline comments
 
/*
 
 *
 
 *  This file is part of the Virtual Leaf.
 
 *
 
 *  The Virtual Leaf is free software: you can redistribute it and/or modify
 
 *  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 <QGraphicsScene>
 
#include <QGraphicsItem>
 
#include <QPainter>
 
#include <QStyleOption>
 
#include <Qt>
 
#include "nodeitem.h"
 
#include "parameter.h"
 

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

	
 
void NodeItem::OnClick(const Qt::MouseButton &mb) {
 
  if (mb == Qt::LeftButton) {
 
    Node *n = &getNode();
 
    n->toggleBoundary();
 
    setColor();
 
    update();
 

	
 
  }
 
}
 

	
 
void NodeItem::setColor(void) {
 

	
 
  static QColor indian_red("IndianRed");
 
  static QColor deep_sky_blue("DeepSkyBlue");
 
  static QColor purple("Purple");
 
  
 
  Node &n=getNode();
 

	
 
  if (n.SamP()) {
 
    setBrush( purple );
 
  } else {
 
    if (n.BoundaryP()) {
 
      setBrush( deep_sky_blue );
 
    } 
 
    else {
 
      setBrush( indian_red );
 
    }
 
  }
 
}
src/output.cpp
Show inline comments
 
/*
 
 *
 
 *  This file is part of the Virtual Leaf.
 
 *
 
 *  The Virtual Leaf is free software: you can redistribute it and/or modify
 
 *  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;
 
    else return FALSE;
 
  } else return TRUE;
 
}
 
 
int FileExistsP(const char *fname) {
 
  
 
  FILE *fp;
 
  fp=fopen(fname,"r");
 
  if (fp==NULL)
 
    return FALSE;
 
  
 
  fclose(fp);
 
  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;
 
  extern Parameter par;
 
 
  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);
 
    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
 
	 string is written in *len */
 
  
 
#define INITIAL_BUFSIZE 100
 
  
 
  char *tmpstring;
 
  int character;
 
  long bufsize;
 
  char *line;
 
  int pos;
 
 
  CheckFile(fp);
 
    
 
  /* first allocate a string with a standard length */
 
  bufsize=INITIAL_BUFSIZE;
 
  MEMORYCHECK(tmpstring=(char *)malloc(bufsize*sizeof(char)));
 
 
  pos=0;
 
  
 
  while ((character=getc(fp))!=EOF && /* read a character and check */
 
		 character!='\n') {
 
 
	
 
	tmpstring[pos]=(char)character;
 
	(pos)++;
 
 
	if (pos >= bufsize) {
 
	  /* line is longer than initial_bufsize, reallocate space */
 
	  bufsize+=INITIAL_BUFSIZE;
 
	  MEMORYCHECK(tmpstring=(char *)realloc(tmpstring,bufsize*sizeof(char)));
 
	  
 
	}
 
		   
 
  }
 
 
 
  if (character==EOF) {
 
	
 
	if (pos==0) {
 
	  /* EOF was reached, while no characters were read */
 
	  free(tmpstring);
 
	  return NULL;
 
 
	}
 
	if (ferror(fp)) {
 
	  error("I/O error in ReadLine(%ld): %s\n",fp, strerror(errno));
 
	}
 
	
 
 
  }
 
  
 
  /* Allocate enough memory for the line */
 
  MEMORYCHECK(line=(char *)malloc((++(pos))*sizeof(char)));
 
 
  strncpy(line,tmpstring,(pos)-1);
 
  free(tmpstring);
 
  
 
  line[pos-1]='\0';
 
  return line;
 
    
 
}
 
 
 
void CheckFile(FILE *fp) 
 
{
 
  if (ftell(fp)<0) {
 
	/* file is probably not open, or another error occured */
 
	error("File error (fp=%ld): %d %s\n",fp,errno,strerror(errno));
 
  }
 
  /* File pointer is ok */
 
}
 
 
char *Chext(char *filename) {
 
 
  /* Chop the extension from a filename */
 
  
 
  /* Search backwards until a dot */
 
  
 
  /* Remember to free the memory allocated by this function */
 
  /* ( free(result) ) */
 
  
 
  /* not yet tested */
 
 
  int i;
 
  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";
 
      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
 
  
 
 
#else
 
  
 
  int status;
 
  char message[MESS_BUF_SIZE];
 
  
 
  status=mkdir(dirname, S_IRWXU); // S_IRWXU: Read, Write, Execute by Owner 
 
  
 
  if (status<0) { // error occurred
 
    
 
    //check for existance
 
    
 
    if (errno==EEXIST) {
 
      
 
      // Check whether it is a directory 
 
      struct stat buf;
 
      stat(dirname, &buf);
 
      if (S_ISDIR(buf.st_mode)) {
 
	// OK 
 
	extern  Parameter par;
 
	if (false /* && par.interactive*/) {
 
	  fprintf(stderr,"Using existing directory %s for data storage.\n",dirname);
 
	  if (!YesNoP("OK?")) {
 
	    // User doesn't agree. Exit
 
	    exit(1);
 
	  }
 
	} 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);
src/qcanvasarrow.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 _QCANVASARROW_H_
 
#define _QCANVASARROW_H_
 

	
 
#include <QGraphicsScene>
 

	
 
class QGraphicsArrowItem : public QGraphicsLineItem {
 

	
 
 public:
 
  QGraphicsArrowItem(QGraphicsItem *parent, QGraphicsScene *c) : QGraphicsLineItem(parent, c) {
 
  };
 
    
 
    void paint ( QPainter *p, const QStyleOptionGraphicsItem *option,
 
		 QWidget *widget ) {
 
      
 

	
 
      widget = NULL; //use assignment merely to obviate compilation warning
 
      option = NULL;
 

	
 
      // construct arrow head
 
      QPointF start=line().p1();
 
      QPointF end=line().p2();
 
      QPointF mid=start + (3./4.)*(end-start);
 
      
 
      double vx=end.x()-start.x();
 
      double vy=end.y()-start.y();
 

	
 
      double length = sqrt(vx*vx+vy*vy);
 
      if (length==0) return;
 
      
 
      // perpendicular vector
 
      double px=-vy/length;
 
      double py=vx/length;
 
      
 
      // Arrow head lines go from end point
 
      // to points about 3/4 of the total arrow, extending sideways about 1/4
 
      // of the arrow length.
 
      
 
      
 
      QPointF arwp1 = mid + QPointF( (int)( (length/4.)*px ),
 
				   (int)( (length/4.)*py ) );
 
      QPointF arwp2 = mid - QPointF( (int)( (length/4.)*px ),
 
				   (int)( (length/4.)*py ) );
 
      
 
      p->setPen(pen());
 
      // Draw arrow head
 
      p->drawLine( end, arwp1 );
 
      p->drawLine( end, arwp2 );
 
      // Draw arrow line
 
      p->drawLine( start, end);
 
    }
 
};
 

	
 
#endif
src/simitembase.cpp
Show inline comments
 
/*
 
 *
 
 *  This file is part of the Virtual Leaf.
 
 *
 
 *  The Virtual Leaf is free software: you can redistribute it and/or modify
 
 *  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 <QBrush>
 
#include "simitembase.h"
 

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

	
 
SimItemBase::SimItemBase( void *v, QGraphicsScene *canvas ) {
 
  canvas = NULL; // use assignment merely to obviate compilation warning
 
    obj=v;
 
};
 

	
 
SimItemBase::~SimItemBase(void) {};
 

	
 

	
 
void SimItemBase::userMove(double dx, double dy) {
 

	
 
  dx = dy = 0.0; // use assignment merely to obviate compilation warning
 
};
src/xmlwrite.cpp
Show inline comments
 
@@ -162,385 +162,385 @@ void Cell::XMLAddCore(xmlNodePtr xmlcell
 
    xmlNewProp(xmlcell, BAD_CAST "boundary", BAD_CAST text.str().c_str());
 
  }
 
  
 
  {
 
    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());
 

	
 
    }
 
  }
 
  
 
  
 

	
 
}
 

	
 

	
 

	
 
void Node::XMLAdd(xmlNodePtr nodes_node) const { 
 
  
 
  // Save the node to a stream so we can reconstruct its state later
 
  xmlNodePtr xmlnode = xmlNewChild(nodes_node, NULL, BAD_CAST "node",NULL);
 

	
 
  
 
  
 
  {
 
    ostringstream text;
 
    text << x;
 
    xmlNewProp(xmlnode, BAD_CAST "x", BAD_CAST text.str().c_str());
 
  }
 
  
 
  {
 
    ostringstream text;
 
    text << y;
 
    xmlNewProp(xmlnode, BAD_CAST "y", BAD_CAST text.str().c_str());
 
  }
 

	
 
  {
 
    ostringstream text;
 
    text << bool_name(fixed);
 
    xmlNewProp(xmlnode, BAD_CAST "fixed", BAD_CAST text.str().c_str());
 
  }
 
  
 
  {
 
    ostringstream text;
 
    text << bool_name(boundary);
 
    xmlNewProp(xmlnode, BAD_CAST "boundary", BAD_CAST text.str().c_str());
 
  }
 

	
 
  {
 
    ostringstream text;
 
    text << bool_name(sam);
 
    xmlNewProp(xmlnode, BAD_CAST "sam", BAD_CAST text.str().c_str());
 
  }
 

	
 
  if (node_set) {
 
    ostringstream text;
 
    text << XMLIO::list_index(m->node_sets.begin(),m->node_sets.end(),node_set);
 
    xmlNewProp(xmlnode, BAD_CAST "nodeset", BAD_CAST text.str().c_str());    
 
  }
 
  
 

	
 
}
 

	
 
void Neighbor::XMLAdd(xmlNodePtr neighbors_node) const {
 
  
 
  xmlNodePtr xmlnode = xmlNewChild(neighbors_node, NULL, BAD_CAST "neighbor",NULL);
 
  {
 
    ostringstream text;
 
    text << cell->Index();
 
    xmlNewProp(xmlnode, BAD_CAST "cell", BAD_CAST text.str().c_str());
 
  }
 

	
 
  {
 
    ostringstream text;
 
    text << nb1->Index();
 
    xmlNewProp(xmlnode, BAD_CAST "nb1", BAD_CAST text.str().c_str());
 
  }
 

	
 
  {
 
    ostringstream text;
 
    text << nb2->Index();
 
    xmlNewProp(xmlnode, BAD_CAST "nb2", BAD_CAST text.str().c_str());
 
  }
 

	
 
}
 

	
 

	
 
// from example code on www.libxml.org:
 
xmlXPathObjectPtr
 
getnodeset (xmlDocPtr doc, xmlChar *xpath){
 
	
 
  xmlXPathContextPtr context;
 
  xmlXPathObjectPtr result;
 

	
 
  context = xmlXPathNewContext(doc);
 
  if (context == NULL) {
 
    //printf("Error in xmlXPathNewContext\n");
 
    return NULL;
 
  }
 
  result = xmlXPathEvalExpression(xpath, context);
 
  xmlXPathFreeContext(context);
 
  if (result == NULL) {
 
    //printf("Error in xmlXPathEvalExpression\n");
 
    return NULL;
 
  }
 
  if(xmlXPathNodeSetIsEmpty(result->nodesetval)){
 
    xmlXPathFreeObject(result);
 
    // printf("No result\n");
 
    return NULL;
 
  }
 
  return result;
 
}
 

	
 

	
 

	
 
int Cell::XMLRead(xmlNode *cur)  {
 
  
 
  xmlNode *n = cur->xmlChildrenNode;
 
  QLocale standardlocale(QLocale::C);
 
  bool ok;
 

	
 
  vector<int> tmp_nodes;
 

	
 
	while(n!=NULL) {
 
    if ((!xmlStrcmp(n->name, (const xmlChar *)"node"))) {
 
      xmlChar *nc = xmlGetProp(n, BAD_CAST "n");
 

	
 
      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++) {
 
    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"))) {
 
	    xmlChar *v_str = xmlGetProp(n, BAD_CAST "n");
 

	
 
	    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");
 
    }
 
    if (v_str != NULL) {
 
      pin_fixed = strtobool( (char *)v_str);
 
      xmlFree(v_str);
 
    }
 
  }
 
      
 
  {
 
    xmlChar *v_str = xmlGetProp(cur, BAD_CAST "at_boundary");
 

	
 
    if (v_str==0) {
 
      unique_warning("Token \"at_boundary\" not found in xmlwrite.cpp at or around line no. 1097");
 
    }
 
    if (v_str != NULL) {
 
      at_boundary = strtobool( (char *)v_str);
 
      xmlFree(v_str);
 
    }
 
  }
 
      
 
  {
 
    xmlChar *v_str = xmlGetProp(cur, BAD_CAST "dead");
 

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

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

	
 
    if (v_str==0) {
 
      unique_warning("Token \"source\" not found in xmlwrite.cpp at or around line no. 1119");
 
    }
 
    if (v_str != NULL) {
 
      source = strtobool( (char *)v_str);
 
      xmlFree(v_str);
 
    }
 
  }
 
      
 
  {
 
    xmlChar *v_str = xmlGetProp(cur, BAD_CAST "boundary");
 

	
 
    if (v_str==0) {
 
      unique_warning("Token \"boundary\" not found in xmlwrite.cpp at or around line no. 1130");
 
    }
 
    if (v_str != NULL) {
 
      for (int i=0;i<4;i++) {
 
	if (!xmlStrcmp( v_str, (const xmlChar *)Cell::boundary_type_names[i])) {
 
	  boundary=(Cell::boundary_type)i;
 
	  break;
 
	}
 
      }
 
      xmlFree(v_str);
 
    }
 
  }
 
  
 
  {
 
    xmlChar *v_str = xmlGetProp(cur, BAD_CAST "div_counter");
 

	
 
    if (v_str==0) {
 
      unique_warning("Token \"div_counter\" not found in xmlwrite.cpp at or around line no. 1119");
 
    }
 
    if (v_str != NULL) {
 
      div_counter = atoi( (char *)v_str);
 
      xmlFree(v_str);
 
@@ -718,951 +718,945 @@ vector<double> XMLIO::XMLReadValArray(xm
 
	//result.push_back(strtod( (const char *)vc, 0));
 
	result.push_back(standardlocale.toDouble((char *)vc, &ok));
 
	if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(char *)vc);
 
	xmlFree(vc);
 
      }
 
      
 
    }
 
    valarray_node = valarray_node->next;
 
  }
 
  return result;
 
}
 

	
 
void Mesh::XMLSave(const char *docname, xmlNode *options) const
 
{
 
	
 
	// 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);
 
	XMLIO::XMLWriteLeafSourceCode(root_node);
 
	XMLIO::XMLWriteReactionsCode(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
 
	 * of root_node node. 
 
	 */
 
	xmlNodePtr xmlcells = xmlNewChild(root_node, NULL, BAD_CAST "cells",NULL);
 
	{
 
		ostringstream text;
 
		text << NCells();
 
		xmlNewProp(xmlcells, BAD_CAST "n", BAD_CAST text.str().c_str());
 
	}
 
	{
 
		ostringstream text;
 
		text << Cell::offset[0];
 
		xmlNewProp(xmlcells, BAD_CAST "offsetx", BAD_CAST text.str().c_str());
 
	}
 
	
 
	{
 
		ostringstream text;
 
		text << Cell::offset[1];
 
		xmlNewProp(xmlcells, BAD_CAST "offsety", BAD_CAST text.str().c_str());
 
	}
 
	
 
	{
 
		ostringstream text;
 
		text << Cell::factor;
 
		xmlNewProp(xmlcells, BAD_CAST "magnification", BAD_CAST text.str().c_str());
 
	}
 
	
 
	{
 
		ostringstream text;
 
		text << cells.front()->BaseArea();
 
		xmlNewProp(xmlcells, BAD_CAST "base_area", BAD_CAST text.str().c_str());
 
	}
 
	
 
	{ 
 
		ostringstream text;
 
		text << Cell::NChem();
 
		xmlNewProp(xmlcells, BAD_CAST "nchem", BAD_CAST text.str().c_str());
 
	}
 
	
 
	for (vector<Cell *>::const_iterator i=cells.begin();
 
		 i!=cells.end();
 
		 i++) {
 
		(*i)->XMLAdd(xmlcells) ;
 
	}
 
	
 
	boundary_polygon->XMLAdd(xmlcells);
 
	
 
	xmlNodePtr xmlwalls = xmlNewChild(root_node, NULL, BAD_CAST "walls",NULL);
 
	{ 
 
		ostringstream text;
 
		text << walls.size();
 
		xmlNewProp(xmlwalls, BAD_CAST "n", BAD_CAST text.str().c_str());
 
	}
 
	
 
	
 
	for (list<Wall *>::const_iterator i=walls.begin();
 
		 i!=walls.end();
 
		 i++) {
 
		(*i)->XMLAdd(xmlwalls) ;
 
	}
 
	
 
	
 
	xmlNodePtr xmlnodesets = xmlNewChild(root_node, NULL, BAD_CAST "nodesets",NULL);
 
	{ 
 
		ostringstream text;
 
		text << node_sets.size();
 
		xmlNewProp(xmlnodesets, BAD_CAST "n", BAD_CAST text.str().c_str());
 
	}
 
	
 
	
 
	for_each( node_sets.begin(), node_sets.end(), 
 
			 bind2nd ( 
 
					  mem_fun( &NodeSet::XMLAdd ),
 
					  xmlnodesets
 
					  ) );
 
	
 
	
 
	// Add option tree for interactive application
 
	if (options) {
 
		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;
 
  xmlNode *cur;
 
  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;
 
	} else {
 
		cerr << "No simtime found in file \n";
 
		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"))) {
 
			XMLReadWallsToCells(cur, &tmp_walls);
 
		}
 
		cur=cur->next;
 
	}
 
    
 
	boundary_polygon->ConstructNeighborList();
 
	boundary_polygon->ConstructConnections();
 
	
 
	for (vector<Cell *>::iterator c=cells.begin();
 
		 c!=cells.end();
 
		 c++) {
 
		
 
		(*c)->ConstructNeighborList();
 
		(*c)->ConstructConnections();
 
		
 
	}
 
	
 
	shuffled_cells.clear();
 
	shuffled_cells = cells;
 
	
 
	MyUrand r(shuffled_cells.size());
 
	random_shuffle(shuffled_cells.begin(),shuffled_cells.end(),r);
 
    
 
}
 

	
 
void Mesh::XMLParseTree(const xmlNode *root_node) {
 
	
 
	XMLReadSimtime(root_node);
 
	XMLReadPars(root_node);
 
	XMLReadGeometry(root_node);
 
	
 
}
 

	
 

	
 
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;
 
	double viz_flux = 0.0;
 
	if (nc!=0) {
 
	  //viz_flux = strtod( (char *)nc, 0);
 
	  double viz_flux = standardlocale.toDouble((const char *)nc, &ok);
 
	  viz_flux = standardlocale.toDouble((const char *)nc, &ok);
 
	  if (!ok) MyWarning::error("Could not convert \"%s\" to double in XMLRead.",(const char *)nc);
 

	
 
	} else {
 
	  // if the info is not there, we really don't care.
 
	  // It is just for visualization anyhow.
 
	  viz_flux = 0.;
 
	}
 
	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;
 
	  }
 
	}
 
				
 
	bool dead = false;
 
	{
 
	  // Note: property "delete" is used to manually clean up wall lists in XML files
 
	  // Simply add property 'delete="true"' to the wall and it will be removed from
 
	  // the mesh. (This saves us from manually reindexing the file). Otherwise do not use it.
 
	  xmlChar *v_str = xmlGetProp(cur, BAD_CAST "delete");
 
					
 
	  if (v_str != 0) {
 
	    dead = strtobool( (char *)v_str);
 
	    xmlFree(v_str);
 
	  }
 
					
 
	}
 
				
 
	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++) {
 
					boundary_polygon->walls.push_back((*tmp_walls)[tmp_walls_ind[i]]);
 
				}
 
			} else {
 
				
 
				int nwalls = tmp_walls_ind.size();
 
				for (int i=0;i<nwalls;i++) {
 
					cells[ci]->walls.push_back((*tmp_walls)[tmp_walls_ind[i]]);	
 
				}
 
				
 
				ci++;
 
			}
 
			
 
		} 
 
		cur=cur->next;
 
	}
 
	
 
	
 
}
 

	
 

	
 
void Mesh::XMLReadNodeSetsToNodes(xmlNode *root) {
 
	
 
	xmlNode *cur = root->xmlChildrenNode;
 
	int ci=0; // cell index
 
	
 
	while (cur!=NULL) {
 
		
 
		
 
		
 
		if ((!xmlStrcmp(cur->name, (const xmlChar *)"node"))) {
 
			
 
			xmlNode *n = cur->xmlChildrenNode;
 
			
 
			while(n!=NULL) {
 
				
 
				xmlChar *nc = xmlGetProp(n, BAD_CAST "nodeset");
 
				
 
				if (nc!=0) {
 
					int nodeset_n = atoi( (char *)nc);
 
					nodes[ci]->node_set = node_sets[nodeset_n];
 
					xmlFree(nc);
 
				} else {
 
					nodes[ci]->node_set = 0;
 
				}
 
				
 
				n = n->next;
 
			}
 
			
 
			ci++;
 
			
 
		} 
 
		cur=cur->next;
 
	}
 
	
 
	
 
}
 

	
 

	
 
void Mesh::XMLReadNodeSets(xmlNode *root) {
 
	
 
	for (vector<NodeSet *>::iterator i=node_sets.begin();
 
		 i!=node_sets.end();
 
		 i++) {
 
		delete *i;
 
	}
 
	
 
	node_sets.clear();
 
	
 
	xmlNode *cur = root->xmlChildrenNode;
 
	
 
	while (cur!=NULL) {
 
		
 
		NodeSet *new_nodeset=0;
 
		
 
		if ((!xmlStrcmp(cur->name, (const xmlChar *)"nodeset"))){
 
			new_nodeset = new NodeSet();
 
			node_sets.push_back(new_nodeset);
 
		} 
 
		
 
		if (new_nodeset == 0) { 
 
			cur = cur->next;
 
			continue;
 
		}
 
		new_nodeset->XMLRead(cur, this);
 
		cur=cur->next;
 
	}
 
	
 
}
 

	
 
void Mesh::XMLReadCells(xmlNode *root) {
 
	
 
	for (vector<Cell *>::iterator i=cells.begin();
 
		 i!=cells.end();
 
		 i++) {
 
		delete *i;
 
	}
 
	
 
	cells.clear();
 
	Cell::NCells() = 0;
 
	
 
	delete boundary_polygon;
 
	
 
	
 
	xmlNode *cur = root->xmlChildrenNode;
 
	
 
	while (cur!=NULL) {
 
		
 
		Cell *new_cell=0;
 
		static int count=0;
 

	
 
		if ((!xmlStrcmp(cur->name, (const xmlChar *)"cell"))){
 
			
 
			new_cell = new Cell(0,0);
 
			new_cell->m = this;
 
			cells.push_back(new_cell);
 
		} else {
 
			if ((!xmlStrcmp(cur->name, (const xmlChar *)"boundary_polygon"))) {
 
				new_cell = boundary_polygon = new BoundaryPolygon(0,0);
 
				boundary_polygon->m = this;
 
			}
 
		}
 
		
 
		if (new_cell == 0) { 
 
			cur = cur->next;
 
			continue;
 
		}
 
		
 
		new_cell->XMLRead(cur);
 
		cur=cur->next;
 
	}
 
	
 
}
 

	
 
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);
 
						}
 
					}
 
				}	  
 
				par_node = par_node->next;
 
			}
 
			
 
		}
 
		cur=cur->next;
 
	}
 
    
 
}
 

	
0 comments (0 inline, 0 general)