Changeset - b85aa64a84ee
[Not reviewed]
default
0 4 0
Michael Guravage - 15 years ago 2010-10-18 10:05:10
michael.guravage@cwi.nl
Replaced getIterations() with getTime().

--
user: Michael Guravage <michael.guravage@cwi.nl>
branch 'default'
changed src/ChangeLog
changed src/VirtualLeaf.cpp
changed src/canvas.cpp
changed src/mesh.h
4 files changed with 12 insertions and 13 deletions:
0 comments (0 inline, 0 general)
src/ChangeLog
Show inline comments
 
2010-10-18    <guravage@caterpie.sen.cwi.nl>
 

	
 
	* VirtualLeaf.cpp (TIMESTEP): Removed getIterations().
 

	
 
	* mesh.h (Mesh): Removed {increment,get}Iterations().
 

	
 
	* canvas.cpp (TimeStepWrap): Replaced getIterations() with getTime().
 

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

	
 
	* mesh.h (Mesh): Added iterations. incrementIterations() and
 
	getIterations().
 

	
 
	* VirtualLeaf.cpp (Plot): Replaced local frame counter with
 
	mesh.incrementIterations().
 

	
 
	* canvas.cpp (TimeStepWrap): Replaced local counter with
 
	mesh.incrementIterations().
 

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

	
 
	* VirtualLeaf.pro: Turned debug off to make all profiles must be
 
	consistant.
 

	
 
	* VirtualLeaf-install.nsi: Tweaked paths to coincide with UNIX
 
	distribution, i.e. VirtualLeaf.exe, its libraries, models, and the
 
	uninstaller all go in the bin directory. And leaves directory
 
	placed under data directory.
 

	
 
	* canvas.cpp (exportCellData): Added a check to inquire before
 
	overwritting an existing file.
 

	
 

	
 
2010-10-14    <merks@cwi.nl>
 

	
 
	* mesh.cpp: In response to referees' comments, added new parameter
 
	"yield_threshold" instead of fixed parameter '4' for yield
 
	threshold.
 

	
 
	* wallitem.cpp: when clicking a wall, both the wall type was
 
	cycled and the transporterdialog popped up. Corrected this - for
 
	wall type cycling, hold the Control button while left
 
	clicking. TransporterDialog only pops up for left click. Also made
 
	sure the wall is redrawn after changing the transporter values.
 

	
 
	* cell.cpp (DivideWalls): accomodated for rename of Circumference -> WallCircumference
 

	
 
	* hull.h: added an operator< to sort Points
 

	
 
	* hull.cpp: added an operator< to sort Points
 

	
 
	* cellbase.cpp (ExactCircumference): I added a new function
 
	ExactCircumference, yielding the circumference of the cell along
 
	its wall_elements
 

	
 
	* VirtualLeaf.cpp: adjust info_string to accomodate for new name
 
	of function CellBase::Circumference -> CellBase::WallCircumference
 

	
 
	* mesh.cpp: corrected Mesh::Compactness, the boundary coordinates
 
	need to be sorted in x,y order for the convex hull algorithm
 
	(thanks Margriet!). I updated CSVExportCellData so it exports the
 
	circumferences of hull and boundary_polygon.
 

	
 

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

	
 
	* VirtualLeafpar.tmpl (export_fn_prefix): changed to 'cell.'
 

	
 
	* canvas.cpp (TimeStepWrap): Removed TimeStamp(). Cell data
 
	filename now incorporates iteration number.
 

	
 
	* canvas.h (MainBase): Removed TimeStamp().
 

	
 

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

	
 

	
 
	* pardialog.h:
 
	* pardialog.cpp:
 
	* parameter.h:
 
	* parameter.cpp: Regenerated to include export_interval and export_fn_prefix.
 

	
 
	* VirtualLeafpar.tmpl: Appended export_interval and export_fn_prefix.
 

	
 
	* canvas.h (MainBase): Declared polymorphic exportCellData() functions.
 

	
 
	* canvas.cpp:
 
	(TimeStamp): New private TimeStamp() function.
 
	(TimeStepWrap): Added invocation of exportCellData().
 
	(exportCellData): Created two polymorphic functions: one with a
 
	single QString argument, the other with no argument. The former is
 
	called from TimeStepWrap() while the latter is called from the
 
	"Export cell areas" item in the file menu.
 

	
 

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

	
 
	* canvas.cpp (exportCellData): Added a Q3FileDialog to inquire
 
	where to write the exportCellData.
 

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

	
 

	
 
	* VirtualLeaf-install.nsi: Grab gpl3.txt from doc directory.
 

	
 
	* canvas.cpp (gpl): gpl3.txt can be either in an ancestor doc
 
	directory (Linux) or a decedent doc directory (Windows, via the
 
	binary installer).
 

	
 
	* VirtualLeaf-install.nsi: Add VirtualLeaf doc directory.
 

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

	
 

	
 
	* gpl3.txt: Moved gpl3.txt from doc to src directory.
 

	
 
	* VirtualLeaf.pro: Added -Wno-write-strings and -Wno-unused-parameter to QMAKE_CXXFLAGS.
 

	
 
	* libplugin.pro: Ditto.
 

	
 
	* parameter.cpp: Result of adding datadir changes to make_parameter_source.pl.
 
	* parameter.h: Ditto.
 

	
 
	* output.h: Declared new function (AppendHomeDirIfPathRelative).
 

	
 
	* output.cpp (AppendHomeDirIfPathRelative): Added new function.
 

	
 
	* canvas.cpp (gpl): Moving gpl3.txt from doc to src obviates the need to docDir.cd("../doc").
 

	
 
	* VirtualLeaf-install.nsi: Grab gpl3.txt from src directory.
 
	Add missing libiconv/bin, libxml2bin and libz/bin directories.
 
	Copy libiconv-2.dll, libxml2.dll and zlib1.dll from relative paths.
 

	
 
	* VirtualLeaf.pro: copy gpl3.txt as part of QMAKE_POST_LINK.
 

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

	
 
	* libplugin.pro: Use correct library path.
 
	* VirtualLeaf.pro: Ditto.
 

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

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

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

	
 

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

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

	
 
	* VirtualLeaf.pro: Disabled console mode.
 

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

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

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

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

	
 
	* Makefile (tutorials): Add tutorials target.
 

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

	
 
	* parameter.cpp: Added particular reassignment of datadir.
 

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	
 

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

	
 

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

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

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

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

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

	
 
	* Makefile: Added top-level Makefile
 

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

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

	
src/VirtualLeaf.cpp
Show inline comments
 
/*
 
 *
 
 *  This file is part of the Virtual Leaf.
 
 *
 
 *  VirtualLeaf is free software: you can redistribute it and/or modify
 
 *  it under the terms of the GNU General Public License as published by
 
 *  the Free Software Foundation, either version 3 of the License, or
 
 *  (at your option) any later version.
 
 *
 
 *  VirtualLeaf is distributed in the hope that it will be useful,
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
 *  GNU General Public License for more details.
 
 *
 
 *  You should have received a copy of the GNU General Public License
 
 *  along with the Virtual Leaf.  If not, see <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 
#include <string>
 
#include <fstream>
 
#include <sstream>
 
#include <cstring>
 
#include <functional> 
 
#include <getopt.h>
 
#include <cerrno>
 
#include "mesh.h"
 
#include "parameter.h"
 
#include "random.h"
 
#include "pi.h"
 
#include "cellitem.h"
 
#include "canvas.h"
 
#include "cell.h"
 
#include "output.h"
 
#include <qwidget.h>
 
#include <q3process.h>
 
#include <qapplication.h>
 
#include <QDesktopWidget>
 
#include <QGraphicsScene>
 
#include <QMessageBox>
 
//Added by qt3to4:
 
#include <QMouseEvent>
 

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

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

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

	
 
extern Parameter par;
 

	
 
MainBase *main_window = 0;
 

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

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

	
 

	
 
class EdgeSource {
 

	
 
public:
 
  void operator() (Cell &c) {
 

	
 
    if (c.AtBoundaryP()) {
 
      cerr << "Cell " << c.Index() << " is a source cell.\n";
 
      c.SetSource(0,par.source);
 
    } else {
 
      cerr << "Cell " << c.Index() << " is _not_ a source cell.\n";
 
    }
 
  }
 
};
 

	
 

	
 

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

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

	
 

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

	
 
Mesh mesh;
 
bool batch=false;
 

	
 
void MainBase::Plot(int resize_stride)
 
{
 

	
 
  clear();
 

	
 
  static int count=0;
 
  if (resize_stride) {
 
    if ( !((count)%resize_stride) ) {
 
      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 << ".jpg";
 
      if (par.storage_stride <= par.xml_storage_stride) {
 
	//frame = (int)mesh.getTime();
 
	frame = mesh.getIterations();
 
	frame = (int)mesh.getTime();
 
      }
 

	
 
      // 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 = (int)mesh.getTime();
 
	frame = mesh.getIterations();
 
	frame = (int)mesh.getTime();
 
      }
 
      // Write XML file every ten plot steps
 
      mesh.XMLSave(fname.str().c_str(), XMLSettingsTree());
 
    }
 
  }
 
 count++;
 
}
 

	
 

	
 

	
 
INIT {
 

	
 
  //mesh.SetSimPlugin(plugin);
 
  if (leaffile) { 
 
    xmlNode *settings;
 
    mesh.XMLRead(leaffile, &settings);
 

	
 
    main_window->XMLReadSettings(settings);
 
    xmlFree(settings);
 
    main_window->UserMessage(QString("Ready. Time is %1").arg(mesh.getTimeHours().c_str()));
 

	
 
  } else {
 
    mesh.StandardInit();
 
  }
 
  
 
  Cell::SetMagnification(1);
 
  Cell::setOffset(0,0);
 
  
 
  FitLeafToCanvas();
 
  Plot();
 

	
 
}
 

	
 
TIMESTEP {
 

	
 
  static int i=0;
 
  static int t=0;
 
  static int ncells;
 

	
 
  if (!batch) {
 
    UserMessage(QString("Time: %1").arg(mesh.getTimeHours().c_str()),0);
 
  }
 

	
 
  ncells=mesh.NCells();
 

	
 

	
 
  double dh;
 

	
 
  if(DynamicCellsP()) {
 
    dh = mesh.DisplaceNodes();
 

	
 
    // Only allow for node insertion, cell division and cell growth
 
    // if the system has equillibrized
 
    // i.e. cell wall tension equillibrization is much faster
 
    // than biological processes, including division, cell wall yielding
 
    // and cell expansion
 
    mesh.InsertNodes(); // (this amounts to cell wall yielding)
 

	
 
    if ( (-dh) < par.energy_threshold) {
 

	
 
      mesh.IncreaseCellCapacityIfNecessary();
 
      mesh.DoCellHouseKeeping();
 
      //mesh.LoopCurrentCells(mem_fun(&plugin->CellHouseKeeping)); // this includes cell division
 

	
 
      // Reaction diffusion	
 
      mesh.ReactDiffuse(par.rd_dt);
 
      t++;
 
      Plot(par.resize_stride);
 
    }
 
  } else {
 
    mesh.ReactDiffuse(par.rd_dt);
 
    Plot(par.resize_stride);
 
  }
 
  i++;
 
  mesh.incrementIterations(); // WHERE SHOULD THIS GO?!
 
  return mesh.getTime();
 
}
 

	
 

	
 

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

	
 

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

	
 

	
 
Parameter par;
 

	
 
int main(int argc,char **argv) {
 

	
 
  try {
 
    int c;
 
    char *leaffile=0;
 
    char *modelfile=0;
 

	
 
    while (1) {
 

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

	
 
      // short option 'p' creates trouble for non-commandline usage on MacOSX. Option -p changed to -P (capital)
 
      static char *short_options = "blm";
 
      c = getopt_long (argc, argv, "bl:m:",
 
		       long_options, &option_index);
 
      if (c == -1)
 
	break;
 

	
 

	
 
      if (c==0) {
 
	printf ("option %s", long_options[option_index].name);
 
	if (optarg)
 
	  printf (" with arg %s", optarg);
 
	printf ("\n");
 

	
 
	c = short_options[option_index];
 
      }
 

	
 
      switch (c) {
 
      case 'b':
 
	cerr << "Running in batch mode\n";
 
	batch=true;
 
	break;
 

	
 
      case 'l':
 
	leaffile=strdup(optarg);
 
	if (!leaffile) {
 
	  throw("Out of memory");
 
	}
 
	printf("Reading leaf state file '%s'\n", leaffile);
 
	break;
 

	
 
      case 'm':
 
	modelfile=strdup(optarg);
 
	if (!modelfile) {
 
	  throw("Out of memory");
 
	}
 
	break;
 

	
 
      case '?':
 
	break;
 

	
 
      default:
 
	printf ("?? getopt returned character code 0%o ??\n", c);
 
      }
 
    }
 

	
 

	
 
    if (optind < argc) {
 
      printf ("non-option ARGV-elements: ");
 
      while (optind < argc)
 
	printf ("%s ", argv[optind++]);
 
      printf ("\n");
 
    }
 

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

	
 

	
 

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

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

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

	
 

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

	
 
	((Main *)main_window)->show();
 
	((Main *)main_window)->resize( ((Main *)main_window)->sizeHint());
 
      } else {
 
        ((Main *)main_window)->showMaximized();
 
      }
 
      
 
      // show "About" window at start up
 
      ((Main *)main_window)->about();
 
    } else {
 
      main_window=new MainBase(canvas, mesh);
 
    }
 

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

	
 
    //    main_window->Init(leaffile);
 

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

	
 
    /*    Cell::SetMagnification(1);
 
    Cell::setOffset(0,0);
 

	
 
    main_window->FitLeafToCanvas();
 

	
 
    main_window->Plot();
 
    */
 
    if (batch) {
 
      double t=0.;
 
      do {
 
	t = main_window->TimeStep();
 
      } while (t < par.maxt);
 
    } else
 
      return app.exec();
 

	
 
  } catch (const char *message) {
 
    if (batch) { 
 
      cerr << "Exception caught:" << endl;
 
      cerr << message << endl;
 
      abort();
 
    } else {
 
      QString qmess=QString("Exception caught: %1").arg(message);
 
      QMessageBox::critical(0, "Critical Error", qmess);
 
      abort();
 
    }
 
  } catch (ios_base::failure) {
 
    stringstream error_message;
 
    error_message << "I/O failure: " << strerror(errno);
 
    if (batch) {
 
      cerr << error_message.str() <<endl;
 
      abort();
 
    } else {
 
      QString qmess(error_message.str().c_str());
 
      QMessageBox::critical(0, "I/O Error", qmess );
 
      abort();
 
    }
 
  }
 
}
 

	
 
/* finis */
src/canvas.cpp
Show inline comments
 
@@ -406,1020 +406,1018 @@ vector <CellItem *> FigureEditor::getInt
 

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

	
 
  delete intersection_line;
 
  intersection_line = 0;
 
  return colliding_cells;
 
}
 

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

	
 

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

	
 

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

	
 
static uint mainCount = 0;
 

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

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

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

	
 
  Q3PopupMenu* file = new Q3PopupMenu( menu );
 

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

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

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

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

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

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

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

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

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

	
 

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

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

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

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

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

	
 

	
 
  menu->insertSeparator();
 

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

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

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

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

	
 
}
 

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

	
 

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

	
 

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

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

	
 
  mainCount++;
 
}
 

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

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

	
 

	
 
void Main::EditParameters()
 
{
 

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

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

	
 
void Main::savePars()
 
{
 

	
 
  stopSimulation();
 

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

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

	
 
  startSimulation();
 
}
 

	
 
void Main::readPars()
 
{
 

	
 
  stopSimulation();
 

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

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

	
 
  emit ParsChanged();
 
}
 

	
 

	
 
void Main::saveStateXML()
 
{
 

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

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

	
 
    } else {
 

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

	
 
    }
 
  }
 
}
 

	
 

	
 

	
 
void Main::snapshot()
 
{
 

	
 

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

	
 
  QString fileName;
 

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

	
 
    } else {
 

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

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

	
 

	
 

	
 
void Main::readPrevStateXML()
 
{
 

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

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

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

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

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

	
 
    readStateXML((const char *)next_file);
 

	
 
  }
 
}
 

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

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

	
 
    FitLeafToCanvas();
 
    
 
    currentFile =  QString(filename);
 

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

	
 

	
 
void Main::readNextStateXML()
 
{
 

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

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

	
 

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

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

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

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

	
 
void Main::readLastStateXML()
 
{
 

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

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

	
 

	
 
    next_file = xml_files.back();
 

	
 
    next_file = currentFile_path+"/"+next_file;
 

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

	
 

	
 
void Main::readFirstStateXML()
 
{
 

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

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

	
 

	
 
    next_file = xml_files.front();
 

	
 
    next_file = currentFile_path+"/"+next_file;
 

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

	
 
void Main::readStateXML()
 
{
 

	
 
  //  extern Mesh mesh;
 

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

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

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

	
 

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

	
 
void Main::about()
 
{
 
  static QMessageBox* about = new QMessageBox
 
    ( "VirtualLeaf V1.0",
 
      "<h3>VirtualLeaf V1.0</h3>"
 
      "<p>"
 
      "An Open Source framework for cell-based modeling of plant tissue growth and development <br>"
 
      "(c) 2005-2008, Roeland Merks <i>et al.</i><br>"
 
      "    <a href=\"http://www.psb.vib-ugent.be\">VIB Department Plant Systems Biology</a>, "
 
      "Ghent, Belgium <br>"
 
      "(c) 2008-2010, <a href=\"http://www.cwi.nl/~merks\">Roeland Merks <i>et al.</i></a> <br>"
 
      "    <a href=\"http://www.cwi.nl\">Centrum Wiskunde & Informatica</a> and <a href=\"http://www.ncsb.nl\">Netherlands Consortium for Systems Biology</a>, Amsterdam, Netherlands <br>"
 
"<br>VirtualLeaf is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.<br>"
 
      "<br>If you use this code for your projects, please cite our paper:"
 
"<br>Merks, Guravage, Inze, and Beemster. An Open Source framework for cell-based modeling of plant tissue growth and development. <i>Plant Physiology,</i> submitted.<br> . <br>"
 
      "<br>Please share your model plugins and extensions at <a href=\"http://virtualleaf.googlecode.com\">http://virtualleaf.googlecode.com</a>.", 
 
      QMessageBox::Information, 1, 0, 0, this, 0, FALSE );
 
  about->setButtonText( 1, "Dismiss" );
 
  about->show();
 
}
 

	
 

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

	
 
  QDir docDir(QApplication::applicationDirPath());
 
  docDir.cd("../doc"); // Where Linux expects gpl3.txt
 
  QString path = docDir.filePath("gpl3.txt");
 
  if (!docDir.exists("gpl3.txt")){
 
    docDir = QApplication::applicationDirPath();
 
    docDir.cd("doc"); // Where Windows expects gpl3.txt
 
    path = docDir.filePath("gpl3.txt");
 
  }
 

	
 
  // At this point path points either to the linux variant, which
 
  // exists, or the windows variant, which may exist. Testing the
 
  // ifstream object will determine whether we've found gpl3.txt.
 

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	
 
void Main::toggleMovieFrames(){}
 

	
 
void Main::toggleLeafBoundary(){}
 

	
 
void Main::toggleDynCells() {}
 

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

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

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

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

	
 

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

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

	
 

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

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

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

	
 

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

	
 
  if ( printer->setup(this) ) {
 

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

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

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

	
 

	
 
void Main::TimeStepWrap(void)
 
{
 
  static int t;
 
  stringstream fname;
 

	
 
  TimeStep();
 

	
 
  //mesh.incrementIterations();
 
  t = mesh.getIterations();
 
  //t = (int)mesh.getTime();
 
  t = (int)mesh.getTime();
 

	
 
  if ((par.export_interval > 0) && !(t%par.export_interval)){
 
    fname << par.datadir << "/" << par.export_fn_prefix;
 
    fname.fill('0');
 
    fname.width(6);
 
    fname << t << ".csv";
 
    this->exportCellData(QString(fname.str().c_str()));
 
  }
 

	
 
  // check number of timesteps
 
  if (t == par.nit) {
 
    emit SimulationDone();
 
  }
 
}
 

	
 

	
 
void Main::RestartSim(void)
 
{
 

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

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

	
 

	
 
void Main::FitCanvasToWindow(void)
 
{
 

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

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

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

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

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

	
 
void Main::FitLeafToCanvas(void) 
 
{
 

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

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

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

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

	
 

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

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

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

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

	
 
  mesh.setTime(0);
 
  Plot();
 

	
 
  editor->FullRedraw();
 
}
 

	
 
void Main::CleanMeshChemicals(void) 
 
{
 

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

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

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

	
 
  editor->FullRedraw();
 
}
 

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

	
 
  mesh.CleanTransporters(clean_transporters);
 

	
 
  mesh.setTime(0);
 
  Plot();
 

	
 
  editor->FullRedraw();
 
}
 

	
 
void Main::RandomizeMesh(void) 
 
{
 

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

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

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

	
 
  mesh.RandomizeChemicals(max_chem, max_transporters);
 

	
 
  Plot();
 
}
 

	
 
void Main::XMLReadSettings(xmlNode *settings) 
 
{
 

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

	
 
xmlNode *Main::XMLSettingsTree(void) 
 
{
 

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

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

	
 
void Main::exportCellData(QString fileName) {
 
  
 
#ifdef QDEBUG  
 
  qDebug() << "exportCellData fileName: " << fileName << endl;
 
#endif
 

	
 
  QFile file(fileName);
 
  if ( file.open( IO_WriteOnly ) ) {
 
    QTextStream stream( &file );
 
    mesh.CSVExportCellData(stream);
 
    mesh.CSVExportMeshData(stream);
 
    file.close();
 
  }
 
}
 

	
 

	
 
void Main::exportCellData() {
 
  QString fileName;
 
  Q3FileDialog *fd = new Q3FileDialog( this, "file dialog", TRUE );
 

	
 
  stopSimulation();
 
  fd->setMode( Q3FileDialog::AnyFile );
 
  if ( fd->exec() == QDialog::Accepted ) {
 
    fileName = fd->selectedFile();
 
    if ( QFile::exists( fileName ) &&
 
	!QMessageBox::question(
 
			       this,
 
			       tr("Overwrite File? -- Cell Data"),
 
			       tr("A file called %1 already exists."
 
				  " Do you want to overwrite it?")
 
			       .arg( fileName ),
 
			       tr("&Yes"), tr("&No"),
 
			       QString::null, 1, 1 ) ) {
 
      this->exportCellData(fileName);
 
    }
 
  }
 
}
 

	
 

	
 
/* finis */
src/mesh.h
Show inline comments
 
/*
 
 *
 
 *  $Id$
 
 *
 
 *  This file is part of the Virtual Leaf.
 
 *
 
 *  VirtualLeaf is free software: you can redistribute it and/or modify
 
 *  it under the terms of the GNU General Public License as published by
 
 *  the Free Software Foundation, either version 3 of the License, or
 
 *  (at your option) any later version.
 
 *
 
 *  VirtualLeaf is distributed in the hope that it will be useful,
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
 *  GNU General Public License for more details.
 
 *
 
 *  You should have received a copy of the GNU General Public License
 
 *  along with the Virtual Leaf.  If not, see <http://www.gnu.org/licenses/>.
 
 *
 
 *  Copyright 2010 Roeland Merks.
 
 *
 
 */
 

	
 

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

	
 
#ifndef _MESH_H_
 
#define _MESH_H_
 

	
 
#include <vector>
 
#include <algorithm>
 
#include <queue>
 
#include <iterator>
 
#include <functional>
 
#ifdef QTGRAPHICS
 
#include <QGraphicsScene>
 
#endif
 
#include "cell.h"
 
#include "node.h"
 
#include "simplugin.h"
 
#include <QVector>
 
#include <QPair>
 
#include <QDebug>
 
#include <QTextStream>
 

	
 
using namespace std;
 
// new queue which rejects duplicate elements
 
template<class T, class C = deque<T> > class unique_queue : public queue<T,C> {
 

	
 
 public:
 
 typedef typename C::value_type value_type;
 
 // reimplements push: reject element if it exists already
 
 void push(const value_type &x) {
 
   if (find (queue<T,C>::c.begin(),queue<T,C>::c.end(),x)==queue<T,C>::c.end()) {
 
     queue<T,C>::c.push_back(x);
 
   }
 
 }
 
 void clear(void) {
 
   queue<T,C>::c.clear();
 
 }
 
};
 

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

	
 

	
 
class Mesh {
 

	
 
  friend class Cell;
 
  friend class Node;
 
  friend class FigureEditor;
 

	
 
 public: 
 
  Mesh(void) {
 
    // Make sure the reserved value is large enough if a cell is added
 
    // in "Divide" when the capacity is insufficient, "cells" might be
 
    // relocated including the current Cell (i.e. the value of *this)
 
    // calling "Mesh::IncreaseCapacityIfNecessary" (from another
 
    // object than Cell, e.g. Mesh) before entering Divide will solve
 
    // this issue (solved now).
 
    cells.reserve(2);
 
    nodes.reserve(500);
 

	
 
    time = 0.;
 
    plugin = 0;
 
    boundary_polygon=0;
 
    iterations = 0;
 

	
 
  };
 
  ~Mesh(void) {
 
    if (boundary_polygon) {
 
      delete boundary_polygon;
 
      boundary_polygon=0;
 
    }
 
  };
 

	
 
  void Clean(void);
 
  Cell &EllipticCell(double xc, double yc, double ra, double rb, int nnodes=10, double rotation=0);
 
  Cell &CircularCell(double xc, double yc, double r, int nnodes=10) {
 
    return EllipticCell(xc, yc, r, r, nnodes, 0);
 
  }
 
  Cell &LeafPrimordium(int n, double pet_length);
 
  Cell &LeafPrimordium2(int n);
 
  Cell *RectangularCell(const Vector ll, const Vector ur, double rotation = 0);
 
  void CellFiles(const Vector ll, const Vector ur);
 

	
 
  inline Cell &getCell(int i) {
 
    if ((unsigned)i<cells.size())
 
      return *cells[i];
 
    else {
 
#ifdef QDEBUG
 
      qDebug() << i << endl;
 
      qDebug() << "size is " << cells.size() << endl;
 
#endif
 
      abort();
 
    }
 
  }
 

	
 
  inline Node &getNode(int i) {
 
    return *nodes[i];    
 
  }
 

	
 
  //double Diffusion(void);
 
  inline int size(void) {
 
    return cells.size();
 
  }
 
  inline int nnodes(void) {
 
    return nodes.size();
 
  }
 

	
 
  template<class Op> void LoopCells(Op f) {
 
    for (vector <Cell *>::iterator i=cells.begin();
 
	 i!=cells.end();
 
	 i++) {
 
      f(**i);
 
    }
 
  }
 

	
 
  template<class Op> void LoopWalls(Op f) {
 
    for (list <Wall *>::iterator i=walls.begin();
 
	 i!=walls.end();
 
	 i++) {
 
      f(**i);
 
    }
 
  }
 

	
 
  // if the amount of cells might increase, during looping, use this template
 
  template<class Op> void LoopCurrentCells(Op f) {
 
    vector<Cell *> current_cells = cells;
 
    for (vector <Cell *>::iterator i=current_cells.begin();
 
	 i!=current_cells.end();
 
	 i++) {
 
      f(**i);
 

	
 
    }
 
  }
 

	
 
  template<class Op> void LoopNodes(Op f) {
 
    for (vector<Node *>::iterator i=nodes.begin();
 
	 i!=nodes.end();
 
	 i++) {
 
      f(**i); 
 
    }
 
  }
 

	
 
  template<class Op> void RandomlyLoopNodes(Op f) {
 

	
 
    MyUrand r(shuffled_nodes.size());
 
    random_shuffle(shuffled_nodes.begin(),shuffled_nodes.end(),r);
 

	
 
    for (vector<Node *>::const_iterator i=shuffled_nodes.begin();
 
	 i!=shuffled_nodes.end();
 
	 i++) {
 
      f(*shuffled_nodes[*i]);
 
    }
 
  }
 

	
 
  template<class Op> void RandomlyLoopCells(Op f) {
 

	
 
    MyUrand r(shuffled_cells.size());
 
    random_shuffle(shuffled_cells.begin(),shuffled_cells.end(),r);
 

	
 
    for (vector<Cell *>::const_iterator i=shuffled_cells.begin();
 
	 i!=shuffled_cells.end();
 
	 i++) {
 
      f(*shuffled_cells[*i]);
 
    }
 
  }
 

	
 
  template<class Op1, class Op2> void LoopCells(Op1 f, Op2 &g) {
 
    for (vector<Cell *>::iterator i=cells.begin();
 
	 i!=cells.end();
 
	 i++) {
 
      f(**i,g); 
 
    }
 
  }
 

	
 
  template<class Op1, class Op2, class Op3> void LoopCells(Op1 f, Op2 &g, Op3 &h) {
 
    for (vector<Cell *>::iterator i=cells.begin();
 
	 i!=cells.end();
 
	 i++) {
 
      f(**i,g,h); 
 
    }
 
  }
 

	
 
  void DoCellHouseKeeping(void) {
 
    vector<Cell *> current_cells = cells;
 
    for (vector<Cell *>::iterator i = current_cells.begin();
 
	 i != current_cells.end();
 
	 i ++) {
 
      plugin->CellHouseKeeping(*i);
 

	
 
      // Call functions of Cell that cannot be called from CellBase, including Division
 
      if ((*i)->flag_for_divide) {
 
	if ((*i)->division_axis) {
 
	  (*i)->DivideOverAxis(*(*i)->division_axis);
 
	  delete (*i)->division_axis;
 
	  (*i)->division_axis = 0;
 
	} else {
 
	  (*i)->Divide();
 
	}
 
	(*i)->flag_for_divide=false;
 
      }
 
    }
 
  }
 

	
 
  // Apply "f" to cell i
 
  // i.e. this is an adapter which allows you to call a function
 
  // operating on Cell on its numeric index index
 
  template<class Op> void cell_index_adapter(Op f,int i) {
 
    f(cells[i]);
 
  }
 

	
 
  double DisplaceNodes(void);
 

	
 
  void BoundingBox(Vector &LowerLeft, Vector &UpperRight);
 
  int NEqs(void) {     int nwalls = walls.size();
 
    int ncells =cells.size();
 
    int nchems = Cell::NChem();
 

	
 
    // two eqs per chemical for each walls, and one eq per chemical for each cell
 
    // This is for generality. For a specific model you may optimize
 
    // this by removing superfluous (empty) equations.
 
    int neqs = 2 * nwalls * nchems + ncells * nchems;
 

	
 
    return neqs;
 
  }
 
  void IncreaseCellCapacityIfNecessary(void) {
 

	
 
    return;
 
    // cerr << "Entering Mesh::IncreaseCellCapacityIfNecessary \n";
 
    // make sure we always have enough space 
 
    // to have each cell divide at least once
 
    //
 
    // Note that we must do this, because Cell::Divide pushes a new Cell
 
    // onto Mesh::cells. As a result, Mesh::cells might be relocated 
 
    // if we are _within_ a Cell object: i.e. pointer "this" will be changed!!
 
    // 
 
    // An alternative solution could be to make "Mesh::cells" a list,
 
    // but this won't work because we need random access for 
 
    // the Monte Carlo algorithm.
 

	
 
    if (2*cells.size()>cells.capacity()) {
 
      cerr << "Increasing capacity to "  << 2*cells.capacity() << endl;
 
      cerr << "Current capacity is " << cells.capacity() << endl;
 
      cells.reserve(cells.capacity()*2);
 
    }
 
  }
 

	
 
  void ReserveMoreCells(int n) {
 
    if (nodes.size()+n>nodes.capacity()) {
 
      nodes.reserve(size()+n);
 
    }
 
  }
 
  double Area(void);
 
  double MeanArea(void) {
 
    double sum=0.;
 
    for (vector<Cell *>::const_iterator i=cells.begin();
 
	 i!=cells.end();
 
	 i++) {
 
      sum+=(*i)->Area();
 
    }
 
    return sum/(double)NCells();
 
  }
 

	
 
  void SetBaseArea(void);
 
  int NCells(void) const {
 
    return cells.size();
 
  }
 
  inline int NNodes(void) const {
 
    return nodes.size();
 
  }
 
  void PrintQueue(ostream &os) {
 
    while (!node_insertion_queue.empty()) {
 
      os << node_insertion_queue.front() << endl;
 
      node_insertion_queue.pop();
 
    }
 
  }
 

	
 
  void InsertNodes(void) {
 
    // insert the nodes in the insertion queue
 
    while (!node_insertion_queue.empty()) {
 

	
 
      //cerr << node_insertion_queue.front() << endl;
 
      InsertNode(node_insertion_queue.front());
 
      node_insertion_queue.pop();
 
    }
 

	
 
  }
 

	
 
  void Clear(); 
 

	
 
  void ReactDiffuse( double delta_t = 1 );
 
  double SumChemical(int ch);
 
  void SetChemical(int ch, double value) {
 
    for (vector<Cell *>::iterator c=cells.begin();
 
	 c!=cells.end();
 
	 c++) {
 
      (*c)->chem[ch]=value;
 
    }
 
  }
 

	
 
  // used for interacing with ODE-solvers (e.g. NRCRungeKutta)
 
  void setValues(double x, double *y);
 
  double *getValues(int *neqs);
 
  void Derivatives(double *derivs);
 
#ifdef QTGRAPHICS
 
  inline void DrawBoundary(QGraphicsScene *c) {
 
    boundary_polygon->Draw(c);
 
  }
 
  void DrawNodes(QGraphicsScene *c) const;
 

	
 
#endif
 
  double max_chem;
 

	
 
  void XMLSave(const char *docname, xmlNode *settings=0) const;
 
  void XMLRead(const char *docname, xmlNode **settings=0, bool geometry = true, bool pars = true, bool simtime = true);
 
  void XMLReadPars(const xmlNode * root_node);
 
  void XMLReadGeometry(const xmlNode *root_node);
 
  void XMLReadSimtime(const xmlNode *root_node);
 
  void XMLReadNodes(xmlNode *cur);
 
  void XMLReadCells(xmlNode *cur);
 
  void XMLParseTree(const xmlNode * root_node);
 
  void XMLReadWalls(xmlNode *cur, vector<Wall *> *tmp_cells);
 
  void XMLReadWallsToCells(xmlNode *root, vector<Wall *> *tmp_walls);
 
  void XMLReadNodeSets(xmlNode *root);
 
  void XMLReadNodeSetsToNodes(xmlNode *root);
 
  void PerturbChem(int chemnum, double range);
 
  void CleanUpCellNodeLists(void);
 
  void CleanUpWalls(void);
 
  void CutAwayBelowLine( Vector startpoint, Vector endpoint );
 
  void CutAwaySAM(void);
 
  void RepairBoundaryPolygon(void);
 
  void Rotate(double angle, Vector center);
 
  void PrintWallList( void );
 
  void TestIllegalWalls(void);
 
  Vector FirstConcMoment(int chem);
 
  inline Vector Centroid(void) {
 
    return boundary_polygon->Centroid();
 
  }
 

	
 
  inline Vector Offset(void) {
 
    return boundary_polygon->Offset();
 
  }
 

	
 
  inline double Factor(void) {
 
    return boundary_polygon->Factor();
 
  }
 

	
 
  void DeleteLooseWalls(void);
 
  void FitLeafToCanvas(double width, double height);
 
  void AddNodeSet(NodeSet *node_set) {
 
    node_sets.push_back(node_set);
 
  }
 

	
 
  void CleanChemicals(const vector<double> &clean_chem);
 
  void CleanTransporters(const vector<double> &clean_transporters);
 
  void RandomizeChemicals(const vector<double> &max_chem, const vector<double> &max_transporters);
 
  inline double getTime(void) const { return time; }
 
  string getTimeHours(void) const; 
 
  inline void setTime(double t) { time = t; }
 
  double CalcProtCellsWalls(int ch) const;  
 
  void SettoInitVals(void);
 
  QVector<qreal> VertexAngles(void);
 
  QVector< QPair<qreal,int> > VertexAnglesValues(void);
 
  void SetSimPlugin(SimPluginInterface *new_plugin) {
 
    plugin=new_plugin;
 
  }
 
  QString ModelID(void) { return plugin?plugin->ModelID():QString("undefined"); }
 
  void StandardInit(void);	
 
  double Compactness(double *res_compactness=0, double *res_area=0, double *res_cell_area=0, double *hull_circumference=0);
 
  void CSVExportCellData(QTextStream &csv_stream) const;
 
  void CSVExportMeshData(QTextStream &csv_stream);
 
  
 
  Node* findNextBoundaryNode(Node*);
 

	
 
  int iterations;
 
  int getIterations(){return this->iterations;}
 
  void incrementIterations(){this->iterations++;}
 

	
 
 private:
 

	
 
  // Data members
 
  vector<Cell *> cells;
 
  vector<Node *> nodes;
 
  list<Wall *> walls; // we need to erase elements from this container frequently, hence a list.
 
 public:
 
  vector<NodeSet *> node_sets;
 
 private:
 
  vector<Node *> shuffled_nodes;
 
  vector<Cell *> shuffled_cells;
 
  unique_queue<Edge> node_insertion_queue;
 
  BoundaryPolygon *boundary_polygon;
 
  double time;
 
  SimPluginInterface *plugin;
 

	
 
  // Private member functions
 
  void AddNodeToCell(Cell *c, Node *n, Node *nb1 , Node *nb2);
 
  void AddNodeToCellAtIndex(Cell *c, Node *n, Node *nb1 , Node *nb2, list<Node *>::iterator ins_pos);
 
  void InsertNode(Edge &e);
 
  inline Node *AddNode(Node *n) {
 
    nodes.push_back(n);
 
    shuffled_nodes.push_back(n);
 
    n->m=this;
 
    return n;
 
  }
 

	
 
  inline Cell *AddCell(Cell *c) {
 
    cells.push_back(c);
 
    shuffled_cells.push_back(c);
 
    //cerr << "Shuffled cell indices:  ";
 
    /*copy(shuffled_cells.begin(),shuffled_cells.end(),ostream_iterator<int>(cerr," "));
 
      cerr << endl;*/
 
    c->m=this;
 
    return c;
 
  }
 

	
 
  void CircumCircle(double x1,double y1,double x2,double y2,double x3,double y3,
 
		    double *xc,double *yc,double *r);
 
};
 
#endif
 

	
 
/* finis */
0 comments (0 inline, 0 general)