Changeset - 8aaffb5565a2
[Not reviewed]
default
0 8 0
Roeland Merks - 15 years ago 2010-10-14 11:45:59
roeland.merks@cwi.nl
Corrected Compactness algorithm. Added algorithms to calculate circumference of convex hull and of the whole morph/

user: Roeland Merks <roeland.merks@cwi.nl>
branch 'default'
8 files changed with 88 insertions and 14 deletions:
0 comments (0 inline, 0 general)
src/ChangeLog
Show inline comments
 
2010-10-14    <merks@cwi.nl>
 

	
 
	* 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-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.Circumference()).arg(c.BoundaryStr());
 
		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++;
 
      }
 

	
 
      // Write high-res JPG snapshot every plot step
 
      Save(fname.str().c_str(), "JPEG",1024,768);
 
    }
 

	
 
    if (!(count%par.xml_storage_stride)) {
 
      stringstream fname;
 
      fname << par.datadir << "/leaf.";
 
      fname.fill('0');
 
      fname.width(6);
 
      fname << frame << ".xml";
 

	
 
      if (par.xml_storage_stride < par.storage_stride) {
 
	frame++;
 
      }
 
      // Write XML file every ten plot steps
 
      mesh.XMLSave(fname.str().c_str(), XMLSettingsTree());
 
    }
 
  }
 
 count++;
 
}
 

	
 

	
 

	
 
INIT {
 

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

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

	
 
  } else {
 
    mesh.StandardInit();
 
  }
 
  
 
  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++;
 
  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/cellbase.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 <cmath>
 
#include <string>
 
#include <sstream>
 
#include <vector>
 
#include <algorithm>
 
#include <functional>
 
#ifdef QTGRAPHICS
 
#include <QGraphicsScene>
 
#include <qpainter.h>
 
#include <qcolor.h>
 
#include <qfont.h>
 
#include <qwidget.h>
 
//Added by qt3to4:
 
#include <Q3PointArray>
 
#include <fstream>
 
#include "nodeitem.h"
 
#include "cellitem.h"
 
#include "qcanvasarrow.h"
 
#endif
 
#include "nodeset.h"
 

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

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

	
 
extern Parameter par;
 

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

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

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

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

	
 

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

	
 
  index=(NCells()++);
 

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

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

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

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

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

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

	
 

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

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

	
 
  index=src.index;
 

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

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

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

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

	
 

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

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

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

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

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

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

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

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

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

	
 

	
 
double CellBase::CalcArea(void) const
 
{
 

	
 
  double loc_area=0.;
 

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

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

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

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

	
 
Vector CellBase::Centroid(void) const
 
{
 

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

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

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

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

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

	
 
  area = fabs(area)/2.0;
 

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

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

	
 

	
 

	
 
void CellBase::SetIntegrals(void) const
 
{
 

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

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

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

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

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

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

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

	
 
  // Calculate length and axes of CellBase
 

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

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

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

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

	
 
  double lambda_b=rhs1+rhs2;
 

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

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

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

	
 
  return 4*sqrt(lambda_b/area);
 
}
 

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

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

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

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

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

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

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

	
 

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

	
 

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

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

	
 
  double lambda_b=rhs1+rhs2;
 

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

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

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

	
 
  return 4*sqrt(lambda_b/my_area);
 
}
 

	
 

	
 
void CellBase::ConstructNeighborList(void)
 
{
 

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

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

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

	
 
  }
 

	
 

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

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

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

	
 

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

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

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

	
 

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

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

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

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

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

	
 
  cellvec.Dump(os);
 

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

	
 

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

	
 

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

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

	
 

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

	
 
double CellBase::ExactCircumference(void) const
 
{
 

	
 
  // simply sum length of all edges
 
  double circumference=0.;
 
    
 
  for (list<Node *>::const_iterator i=nodes.begin(); i!=(nodes.end()); i++) {
 

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

	
 
    double dx=((*i_plus_1)->x-(*i)->x);
 
    double dy=((*i_plus_1)->y-(*i)->y);
 
    double l=sqrt(dx*dx+dy*dy);
 
    //    f << (*i)->x << " " << (*i)->y << " " << (*i_plus_1)->x << " " << (*i_plus_1)->y << " " << l << endl;
 

	
 
    circumference += l;
 
  }
 

	
 
  return circumference;
 
} 
 

	
 
/* finis*/
src/cellbase.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.
 
 *
 
 */
 

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

	
 
#ifndef _CELLBASE_H_
 
#define _CELLBASE_H_
 

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

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

	
 
extern Parameter par;
 
using namespace std;
 

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

	
 
struct ParentInfo {
 

	
 
  Vector polarization;
 
  double PINmembrane;
 
  double PINendosome;
 
};
 

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

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

	
 
class CellBase :  public QObject, public Vector 
 
{
 

	
 
  Q_OBJECT
 

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

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

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

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

	
 

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

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

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

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

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

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

	
 
  ostream &print(ostream &os) const;
 

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

	
 
    int nchem = NChem();
 

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

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

	
 

	
 
  //void print_nblist(void) const;
 

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

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

	
 
  boundary_type Boundary(void) const { return boundary; }
 

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

	
 
  double CalcArea(void) const;
 

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

	
 
  Vector Centroid(void) const;
 

	
 
  void SetIntegrals(void) const;
 

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

	
 

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

	
 

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

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

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

	
 
  inline double TargetArea(void) { return target_area; }
 

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

	
 
  inline double Stiffness(void) { return stiffness; }
 

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

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

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

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

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

	
 
    return sum;
 
  }
 

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

	
 
  void Dump(ostream &os) const;
 

	
 
  QString printednodelist(void);
 

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

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

	
 
  void CheckForDivision(void);
 

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

	
 
  bool AtBoundaryP(void) const;
 

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

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

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

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

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

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

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

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

	
 

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

	
 
    }
 
    return sum;
 
  }
 

	
 
  inline int NumberOfDivisions(void) { return div_counter; }
 

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

	
 
    }
 
    return sum;
 
  }
 

	
 

	
 

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

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

	
 

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

	
 
  inline double TargetLength() const { return target_length; } 
 

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

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

	
 
  int index;
 

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

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

	
 
  // DATA MEMBERS
 

	
 
  // list of nodes, in clockwise order
 

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

	
 
  list<Wall *> walls;
 

	
 
  double *chem;
 
  double *new_chem;
 

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

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

	
 
  bool fixed;
 
  bool pin_fixed;
 
  bool at_boundary; 
 
  bool dead; 
 
  bool flag_for_divide;
 

	
 
  Vector *division_axis;
 
  int cell_type;
 

	
 
  // for length constraint
 
  mutable double intgrl_xx, intgrl_xy, intgrl_yy, intgrl_x, intgrl_y;
 

	
 
  bool source;
 
  Vector cellvec;
 

	
 
  // STATIC DATAMEMBERS MOVED TO CLASS
 
  static CellsStaticDatamembers *static_data_members;
 
  double source_conc;
 
  int source_chem;
 

	
 
  // PRIVATE MEMBER FUNCTIONS
 
  inline static void ClearNCells(void)
 
  {
 
    NCells()=0;
 
  }
 

	
 
  bool marked;
 
  int div_counter;
 
};
 

	
 
ostream &operator<<(ostream &os, const CellBase &v);
 

	
 
inline Vector PINdir(CellBase *here, CellBase *nb, Wall *w)
 
{
 
  return w->getTransporter( here, 1)  *  w->getInfluxVector(here);
 
}
 

	
 
#endif
 

	
 
/* finis*/
src/hull.cpp
Show inline comments
 
// Copyright 2001, softSurfer (www.softsurfer.com)
 
// This code may be freely used and modified for any purpose
 
// providing that this copyright notice is included with it.
 
// SoftSurfer makes no warranty for this code, and cannot be held
 
// liable for any real or imagined damage resulting from its use.
 
// Users of this code must verify correctness for their application.
 

	
 
// Assume that a class is already given for the object:
 
//    Point with coordinates {float x, y;}
 
//===================================================================
 

	
 
// isLeft(): tests if a point is Left|On|Right of an infinite line.
 
//    Input:  three points P0, P1, and P2
 
//    Return: >0 for P2 left of the line through P0 and P1
 
//            =0 for P2 on the line
 
//            <0 for P2 right of the line
 
//    See: the January 2001 Algorithm on Area of Triangles
 

	
 
#include "hull.h"
 

	
 

	
 
inline float
 
isLeft( Point P0, Point P1, Point P2 )
 
{
 
    return (P1.x - P0.x)*(P2.y - P0.y) - (P2.x - P0.x)*(P1.y - P0.y);
 
}
 

	
 
// required to sort points (e.g. Qt's qSort())
 
bool operator<(const Point & p1, const Point & p2) {
 
  if (p1.y<p2.y) return true;
 
  else
 
    if (p1.y>p2.y) return false;
 
    else 
 
      if (p1.x<p2.x) return true;
 
      else
 
	return false;
 
}
 

	
 
//===================================================================
 
 
 

	
 
// chainHull_2D(): Andrew's monotone chain 2D convex hull algorithm
 
//     Input:  P[] = an array of 2D points
 
//                   presorted by increasing x- and y-coordinates
 
//             n = the number of points in P[]
 
//     Output: H[] = an array of the convex hull vertices (max is n)
 
//     Return: the number of points in H[]
 
int
 
chainHull_2D( Point* P, int n, Point* H )
 
{
 
    // the output array H[] will be used as the stack
 
    int    bot=0, top=(-1);  // indices for bottom and top of the stack
 
    int    i;                // array scan index
 

	
 
    // Get the indices of points with min x-coord and min|max y-coord
 
    int minmin = 0, minmax;
 
    float xmin = P[0].x;
 
    for (i=1; i<n; i++)
 
        if (P[i].x != xmin) break;
 
    minmax = i-1;
 
    if (minmax == n-1) {       // degenerate case: all x-coords == xmin
 
        H[++top] = P[minmin];
 
        if (P[minmax].y != P[minmin].y) // a nontrivial segment
 
            H[++top] = P[minmax];
 
        H[++top] = P[minmin];           // add polygon endpoint
 
        return top+1;
 
    }
 

	
 
    // Get the indices of points with max x-coord and min|max y-coord
 
    int maxmin, maxmax = n-1;
 
    float xmax = P[n-1].x;
 
    for (i=n-2; i>=0; i--)
 
        if (P[i].x != xmax) break;
 
    maxmin = i+1;
 

	
 
    // Compute the lower hull on the stack H
 
    H[++top] = P[minmin];      // push minmin point onto stack
 
    i = minmax;
 
    while (++i <= maxmin)
 
    {
 
        // the lower line joins P[minmin] with P[maxmin]
 
        if (isLeft( P[minmin], P[maxmin], P[i]) >= 0 && i < maxmin)
 
            continue;          // ignore P[i] above or on the lower line
 

	
 
        while (top > 0)        // there are at least 2 points on the stack
 
        {
 
            // test if P[i] is left of the line at the stack top
 
            if (isLeft( H[top-1], H[top], P[i]) > 0)
 
                break;         // P[i] is a new hull vertex
 
            else
 
                top--;         // pop top point off stack
 
        }
 
        H[++top] = P[i];       // push P[i] onto stack
 
    }
 

	
 
    // Next, compute the upper hull on the stack H above the bottom hull
 
    if (maxmax != maxmin)      // if distinct xmax points
 
        H[++top] = P[maxmax];  // push maxmax point onto stack
 
    bot = top;                 // the bottom point of the upper hull stack
 
    i = maxmin;
 
    while (--i >= minmax)
 
    {
 
        // the upper line joins P[maxmax] with P[minmax]
 
        if (isLeft( P[maxmax], P[minmax], P[i]) >= 0 && i > minmax)
 
            continue;          // ignore P[i] below or on the upper line
 

	
 
        while (top > bot)    // at least 2 points on the upper stack
 
        {
 
            // test if P[i] is left of the line at the stack top
 
            if (isLeft( H[top-1], H[top], P[i]) > 0)
 
                break;         // P[i] is a new hull vertex
 
            else
 
                top--;         // pop top point off stack
 
        }
 
        H[++top] = P[i];       // push P[i] onto stack
 
    }
 
    if (minmax != minmin)
 
        H[++top] = P[minmin];  // push joining endpoint onto stack
 

	
 
    return top+1;
 
}
 

	
src/hull.h
Show inline comments
 
#ifndef _HULL_H_
 
#define _HULL_H_
 

	
 
// Class point needed by 2D convex hull code
 
class Point {
 

	
 
public:
 
  Point(float xx, float yy) {
 
    x=xx;
 
    y=yy;
 
  }
 
  Point(void) {
 
    x=0; y=0;
 
  }
 
  float x,y;
 

	
 

	
 
};
 

	
 
// required to sort points (e.g. Qt's qSort())
 
bool operator<(const Point & p1, const Point & p2);
 

	
 
int chainHull_2D( Point* P, int n, Point* H );
 

	
 
#endif
src/mesh.cpp
Show inline comments
 
@@ -437,1628 +437,1645 @@ public:
 
    ixx=sixx;
 
    ixy=sixy;
 
    iyy=siyy;
 
  }
 
};
 

	
 
void Mesh::Clear(void) {
 

	
 
  // clear nodes
 
  for (vector<Node *>::iterator i=nodes.begin(); i!=nodes.end(); i++) {
 
    delete *i;
 
  }
 

	
 
  nodes.clear();
 
  Node::nnodes=0;
 

	
 
  node_insertion_queue.clear();
 
  // Clear NodeSets
 
  for (vector<NodeSet *>::iterator i=node_sets.begin(); i!=node_sets.end(); i++) {
 
    delete *i;
 
  }
 

	
 
  node_sets.clear();
 
  time = 0;
 

	
 
  // clear cells
 

	
 
  for (vector<Cell *>::iterator i=cells.begin(); i!=cells.end(); i++) {
 
    delete *i;
 
  }
 

	
 
  cells.clear();
 
  Cell::NCells() = 0;
 

	
 
  if (boundary_polygon) {
 
    delete boundary_polygon;
 
    boundary_polygon=0;
 
  }
 

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

	
 
  walls.clear();
 
  WallBase::nwalls = 0;
 
  //tmp_walls->clear();
 

	
 
  shuffled_cells.clear();
 
  shuffled_nodes.clear();
 
 
 
#ifdef QDEBUG
 
  qDebug() << "cells.size() = " << cells.size() << endl;
 
  qDebug() << "walls.size() = " << walls.size() << endl;
 
  qDebug() << "nodes.size() = " << nodes.size() << endl;
 
#endif
 
}
 

	
 
double Mesh::DisplaceNodes(void) {
 

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

	
 
  double sum_dh=0;
 

	
 
  list<DeltaIntgrl> delta_intgrl_list;
 

	
 
  for_each( node_sets.begin(), node_sets.end(), mem_fun( &NodeSet::ResetDone ) );
 

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

	
 
    //int n=shuffled_nodes[*i];
 
    Node &node(**i);
 

	
 
    // Do not allow displacement if fixed
 
    //if (node.fixed) continue;
 

	
 
    if (node.DeadP()) continue;
 

	
 
    // Attempt to move this cell in a random direction
 
    double rx=par.mc_stepsize*(RANDOM()-0.5); // was 100.
 
    double ry=par.mc_stepsize*(RANDOM()-0.5);
 

	
 
    // Uniform with a circle of radius par.mc_stepsize
 
    /* double r = RANDOM() * par.mc_stepsize;
 
       double th = RANDOM()*2*Pi;
 

	
 
       double rx = r * cos(th);
 
       double ry = r * sin(th);
 
    */
 
    Vector new_p(node.x+rx,node.y+ry,0);
 
    Vector old_p(node.x,node.y,0);
 

	
 
    /* if (node.boundary  && boundary_polygon->MoveSelfIntersectsP(n,  new_p )) {
 
    // reject if move of boundary results in self intersection
 
    continue;
 
    }*/
 

	
 

	
 
    if (node.node_set) {
 
      // move each node set only once
 
      if (!node.node_set->DoneP()) 
 
	node.node_set->AttemptMove(rx,ry);
 

	
 
    } else {
 

	
 
      // for all cells to which this node belongs:
 
      //   calculate energy difference
 

	
 
      double area_dh=0.;
 
      double length_dh=0.;
 
      double bending_dh=0.;
 
      double cell_length_dh=0.;
 
      double alignment_dh=0.;
 

	
 
      double old_l1=0.,old_l2=0.,new_l1=0.,new_l2=0.;
 

	
 
      double sum_stiff=0.;
 
      double dh=0.;
 

	
 
      for (list<Neighbor>::const_iterator cit=node.owners.begin(); cit!=node.owners.end(); cit++) {
 

	
 
	
 
	Cell &c=*((Cell *)(cit->cell));
 

	
 
	if (c.MoveSelfIntersectsP(&node,  new_p )) {
 
		
 
	  // reject if move results in self intersection
 
	  //
 
	  // I know: using goto's is bad practice... except when jumping out
 
	  // of deeply nested loops :-)
 
	  //cerr << "Rejecting due to self-intersection\n";
 
	  goto next_node;
 
	}
 

	
 
	// summing stiffnesses of cells. Move has to overcome this minimum required energy.
 
	sum_stiff += c.stiffness;
 
	// area - (area after displacement): see notes for derivation
 
	
 
	Vector i_min_1 = *(cit->nb1);
 
	//Vector i_plus_1 = m->getNode(cit->nb2);
 
	Vector i_plus_1 = *(cit->nb2);
 

	
 

	
 
	// We must double the weights for the perimeter (otherwise they start bulging...)
 
	double w1, w2;
 
	if (node.boundary && cit->nb1->boundary) 
 
#ifdef FLEMING
 
	  w1 = par.rel_perimeter_stiffness;
 
#else
 
	w1=2;
 
#endif
 
	else
 
	  w1 = 1;
 

	
 
	if (node.boundary && cit->nb2->boundary) 
 
#ifdef FLEMING
 
	  w2 = par.rel_perimeter_stiffness;
 
#else
 
	w2 = 2;
 
#endif
 
	else 
 
	  w2 = 1;
 

	
 
	//if (cit->cell>=0) {
 
	if (!cit->cell->BoundaryPolP()) {
 
	  double delta_A = 0.5 * ( ( new_p.x - old_p.x ) * (i_min_1.y - i_plus_1.y) +
 
				   ( new_p.y - old_p.y ) * ( i_plus_1.x - i_min_1.x ) );
 

	
 
	  area_dh +=  delta_A * (2 * c.target_area - 2 * c.area + delta_A);
 

	
 

	
 
	  // cell length constraint
 
	  // expensive and not always needed
 
	  // so we check the value of lambda_celllength
 

	
 
	  if (/* par.lambda_celllength */  cit->cell->lambda_celllength) {
 

	
 
	    double delta_ix = 
 
	      (i_min_1.x + new_p.x)
 
	      * (new_p.x * i_min_1.y- i_min_1.x * new_p.y) +
 
	      (new_p.x + i_plus_1.x)
 
	      * (i_plus_1.x * new_p.y- new_p.x * i_plus_1.y) -
 

	
 
	      (i_min_1.x + old_p.x)
 
	      * (old_p.x * i_min_1.y- i_min_1.x * old_p.y) -
 
	      (old_p.x + i_plus_1.x)
 
	      * (i_plus_1.x * old_p.y - old_p.x * i_plus_1.y);
 

	
 

	
 
	    double delta_iy =
 
	      (i_min_1.y + new_p.y)
 
	      * (new_p.x * i_min_1.y- i_min_1.x * new_p.y) +
 
	      (new_p.y + i_plus_1.y)
 
	      * (i_plus_1.x * new_p.y- new_p.x * i_plus_1.y) -
 

	
 
	      (i_min_1.y + old_p.y)
 
	      * (old_p.x * i_min_1.y- i_min_1.x * old_p.y) -
 
	      (old_p.y + i_plus_1.y)
 
	      * (i_plus_1.x * old_p.y - old_p.x * i_plus_1.y);
 

	
 

	
 
	    double delta_ixx = 
 
	      (new_p.x*new_p.x+
 
	       i_min_1.x*new_p.x+
 
	       i_min_1.x*i_min_1.x ) *
 
	      (new_p.x*i_min_1.y - i_min_1.x*new_p.y) +
 

	
 
	      (i_plus_1.x*i_plus_1.x+
 
	       new_p.x*i_plus_1.x+
 
	       new_p.x*new_p.x ) *
 
	      (i_plus_1.x*new_p.y - new_p.x*i_plus_1.y) -
 

	
 
	      (old_p.x*old_p.x+
 
	       i_min_1.x*old_p.x+
 
	       i_min_1.x*i_min_1.x ) *
 
	      (old_p.x*i_min_1.y - i_min_1.x*old_p.y) -
 

	
 
	      (i_plus_1.x*i_plus_1.x+
 
	       old_p.x*i_plus_1.x+
 
	       old_p.x*old_p.x ) *
 
	      (i_plus_1.x*old_p.y - old_p.x*i_plus_1.y);
 

	
 

	
 
	    double delta_ixy =
 
	      (i_min_1.x*new_p.y-
 
	       new_p.x*i_min_1.y)*
 
	      (new_p.x*(2*new_p.y+i_min_1.y)+
 
	       i_min_1.x*(new_p.y+2*i_min_1.y)) +
 

	
 
	      (new_p.x*i_plus_1.y-
 
	       i_plus_1.x*new_p.y)*
 
	      (i_plus_1.x*(2*i_plus_1.y+new_p.y)+
 
	       new_p.x*(i_plus_1.y+2*new_p.y)) -
 

	
 
	      (i_min_1.x*old_p.y-
 
	       old_p.x*i_min_1.y)*
 
	      (old_p.x*(2*old_p.y+i_min_1.y)+
 
	       i_min_1.x*(old_p.y+2*i_min_1.y)) -
 

	
 
	      (old_p.x*i_plus_1.y-
 
	       i_plus_1.x*old_p.y)*
 
	      (i_plus_1.x*(2*i_plus_1.y+old_p.y)+
 
	       old_p.x*(i_plus_1.y+2*old_p.y));
 

	
 

	
 
	    double delta_iyy = 
 
	      (new_p.x*i_min_1.y-
 
	       i_min_1.x*new_p.y)*
 
	      (new_p.y*new_p.y+
 
	       i_min_1.y*new_p.y+
 
	       i_min_1.y*i_min_1.y ) + 
 

	
 
	      (i_plus_1.x*new_p.y-
 
	       new_p.x*i_plus_1.y)*
 
	      (i_plus_1.y*i_plus_1.y+
 
	       new_p.y*i_plus_1.y+
 
	       new_p.y*new_p.y ) -
 

	
 
	      (old_p.x*i_min_1.y-
 
	       i_min_1.x*old_p.y)*
 
	      (old_p.y*old_p.y+
 
	       i_min_1.y*old_p.y+
 
	       i_min_1.y*i_min_1.y ) -
 

	
 
	      (i_plus_1.x*old_p.y-
 
	       old_p.x*i_plus_1.y)*
 
	      (i_plus_1.y*i_plus_1.y+
 
	       old_p.y*i_plus_1.y+
 
	       old_p.y*old_p.y );
 

	
 
	    delta_intgrl_list.push_back(DeltaIntgrl(delta_A,delta_ix,delta_iy,delta_ixx,delta_ixy,delta_iyy));
 

	
 
	    Vector old_axis;
 
	    double old_celllength = c.Length(&old_axis);
 
	    old_axis=old_axis.Normalised().Perp2D();
 

	
 
	    // calculate length after proposed update
 
	    double intrx=(c.intgrl_x-delta_ix)/6.;
 
	    double intry=(c.intgrl_y-delta_iy)/6.;
 
	    double ixx=((c.intgrl_xx-delta_ixx)/12.)-(intrx*intrx)/(c.area-delta_A);
 
	    double ixy=((c.intgrl_xy-delta_ixy)/24.)+(intrx*intry)/(c.area-delta_A);
 
	    double iyy=((c.intgrl_yy-delta_iyy)/12.)-(intry*intry)/(c.area-delta_A);
 

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

	
 
	    double lambda_b=rhs1+rhs2;
 

	
 

	
 
	    double new_celllength=4*sqrt(lambda_b/(c.area-delta_A));
 
	    //cerr << "new_celllength = "  << new_celllength << endl;
 
	    //cerr << "target_length = "  << c.target_length << endl;
 

	
 
	    cell_length_dh += c.lambda_celllength * ( DSQR(c.target_length - new_celllength) - DSQR(c.target_length-old_celllength) );
 

	
 
	    Vector norm_long_axis(lambda_b - ixx, ixy, 0);
 
	    norm_long_axis.Normalise();
 

	
 
	    double alignment_before = InnerProduct(old_axis, c.cellvec);
 
	    double alignment_after = InnerProduct(norm_long_axis, c.cellvec);
 

	
 
	    /* cerr << "Delta alignment = " << alignment_before - alignment_after << endl;
 
	       cerr << "Old alignment is " << alignment_before << ", new alignment is " << alignment_after << endl;
 
	       cerr << "Old axis is " << old_axis << ", new axis is " << norm_long_axis << endl; 
 
	    */
 
	    alignment_dh += alignment_before - alignment_after;
 

	
 
	    /* cerr << "alignment_dh  = " << alignment_dh << endl;
 
	       cerr << "cellvec = " << c.cellvec << endl;*/
 

	
 
	  } else {
 
	    // if we have no length constraint, still need to update area
 
	    delta_intgrl_list.push_back(DeltaIntgrl(delta_A,0,0,0,0,0));
 

	
 
	  }
 

	
 
	  old_l1=(old_p-i_min_1).Norm();
 
	  old_l2=(old_p-i_plus_1).Norm();
 
	  new_l1=(new_p-i_min_1).Norm();
 
	  new_l2=(new_p-i_plus_1).Norm();
 

	
 

	
 

	
 

	
 
	  static int count=0;
 
	  // Insertion of nodes (cell wall yielding)
 
	  if (!node.fixed) {
 
	    if (old_l1 > 4*Node::target_length && !cit->nb1->fixed) {
 
	      node_insertion_queue.push( Edge(cit->nb1, &node) );
 
	    }
 
	    if (old_l2 > 4*Node::target_length && !cit->nb2->fixed) {
 
	      node_insertion_queue.push( Edge(&node, cit->nb2 ) );
 
	    }
 
	    count++;
 

	
 
	  }
 

	
 

	
 
	
 
	  length_dh += 2*Node::target_length * ( w1*(old_l1 - new_l1) + 
 
						 w2*(old_l2 - new_l2) ) +
 
	    w1*(DSQR(new_l1) 
 
		- DSQR(old_l1)) 
 
	    + w2*(DSQR(new_l2) 
 
		  - DSQR(old_l2));
 

	
 

	
 
	 
 

	
 

	
 
	}
 

	
 
	// bending energy also holds for outer boundary
 
	// first implementation. Can probably be done more efficiently
 
	// calculate circumcenter radius (gives local curvature)
 
	// the ideal bending state is flat... (K=0)
 
		  {
 
	  // strong bending energy to resist "cleaving" by division planes
 
	  double r1, r2, xc, yc;
 
	  CircumCircle(i_min_1.x, i_min_1.y, old_p.x, old_p.y, i_plus_1.x, i_plus_1.y,
 
		       &xc,&yc,&r1);
 
	  CircumCircle(i_min_1.x, i_min_1.y, new_p.x, new_p.y, i_plus_1.x, i_plus_1.y,
 
		       &xc,&yc, &r2);
 

	
 
	  if (r1<0 || r2<0) {
 
	    MyWarning::warning("r1 = %f, r2 = %f",r1,r2);
 
	  }
 
	  bending_dh += DSQR(1/r2 - 1/r1);
 

	
 
	}
 

	
 

	
 
      }
 

	
 
     
 
		
 

	
 
      dh = 	area_dh + cell_length_dh +
 
	par.lambda_length * length_dh + par.bend_lambda * bending_dh + par.alignment_lambda * alignment_dh;
 

	
 
         //(length_constraint_after - length_constraint_before);
 

	
 
      if (node.fixed) {
 

	
 
	// search the fixed cell to which this node belongs
 
	// and displace these cells as a whole
 
	// WARNING: undefined things will happen for connected fixed cells...
 
	for (list<Neighbor>::iterator c=node.owners.begin(); c!=node.owners.end(); c++) {
 
	  if (!c->cell->BoundaryPolP() && c->cell->FixedP()) {
 
	    sum_dh+=c->cell->Displace(rx,ry,0);
 
	  }
 
	}
 
      } else {
 

	
 

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

	
 
	  // update areas of cells
 
	  list<DeltaIntgrl>::const_iterator di_it = delta_intgrl_list.begin();
 
	  for (list<Neighbor>::iterator cit=node.owners.begin(); cit!=node.owners.end(); ( cit++) ) {
 
	    if (!cit->cell->BoundaryPolP()) {
 
	      cit->cell->area -= di_it->area;
 
	      if (par.lambda_celllength) {
 
		cit->cell->intgrl_x -= di_it->ix;
 
		cit->cell->intgrl_y -= di_it->iy;
 
		cit->cell->intgrl_xx -= di_it->ixx;
 
		cit->cell->intgrl_xy -= di_it->ixy;
 
		cit->cell->intgrl_yy -= di_it->iyy;
 
	      }
 
	      di_it++;
 
	    }
 
	  }
 

	
 
	  double old_nodex, old_nodey;
 

	
 
	  old_nodex=node.x;
 
	  old_nodey=node.y;
 

	
 
	  node.x = new_p.x;
 
	  node.y = new_p.y;
 

	
 
	  for (list<Neighbor>::iterator cit=node.owners.begin();
 
	       cit!=node.owners.end();
 
	       ( cit++) ) {
 

	
 
	    /*   if (cit->cell >= 0 && cells[cit->cell].SelfIntersect()) {
 
		 node.x = old_nodex;		       
 
		 node.y = old_nodey;
 
		 goto next_node;
 
		 }*/
 
	  }
 
	  sum_dh += dh;
 
	}  
 
      }
 
    } 
 
  next_node:
 
    delta_intgrl_list.clear();//dA_list.clear();
 

	
 
  }
 

	
 
  return sum_dh;
 
}
 

	
 

	
 
void Mesh::InsertNode(Edge &e) {
 

	
 

	
 
  // Construct a new node in the middle of the edge
 
  Node *new_node = AddNode( new Node ( ( *e.first + *e.second )/2 ) );
 

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

	
 
  // The new node is part of the boundary only if both its neighbors are boundary nodes and the boundray proceeds from first to second.
 
  new_node->boundary = (e.first->BoundaryP() && e.first->BoundaryP()) && ((findNextBoundaryNode(e.first))->Index() == e.second->Index());
 
  new_node->fixed = e.first->fixed && e.second->fixed;
 
  new_node->sam = new_node->boundary && (e.first->sam || e.second->sam);
 

	
 
  // insert it into the boundary polygon;
 
  /* if (new_node->boundary) {
 

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

	
 
  boundary_polygon->nodes.insert(((ins_pos--)!=boundary_polygon->nodes.begin()?ins_pos:(--boundary_polygon->nodes.end())), new_node);
 

	
 
  // .. set the neighbors of the new node ...
 
  // in this case e.second and e.first are inverted
 
  new_node->owners.push_back( Neighbor(boundary_polygon, e.second, e.first ) );
 
  //cerr << "pushing back " << Neighbor(boundary_polygon->index, e.second, e.first ) << endl;
 
  } else {
 
  // insert before second node, so leave ins_pos as it is,
 
  // that is incremented
 
  boundary_polygon->nodes.insert(ins_pos, new_node);
 

	
 
  // .. set the neighbors of the new node ...
 
  new_node->owners.push_back( Neighbor(boundary_polygon, e.first, e.second ) );
 
  // cerr << "pushing back " << Neighbor(boundary_polygon->index, e.second, e.first ) << endl;
 
  }
 

	
 
  }*/
 

	
 

	
 
  list<Neighbor> owners;
 

	
 
  // push all cells owning the two nodes of the divided edges
 
  // onto a list
 
  copy(e.first->owners.begin(),
 
       e.first->owners.end(),
 
       back_inserter(owners));
 
  copy(e.second->owners.begin(),
 
       e.second->owners.end(),
 
       back_inserter(owners));
 

	
 
  //copy(owners.begin(), owners.end(), ostream_iterator<Neighbor>(cerr, " "));
 
  //cerr << endl;
 

	
 
  // sort the nodes
 
  owners.sort( mem_fun_ref( &Neighbor::Cmp ) );
 

	
 
  //  extern ofstream debug_stream;
 

	
 
  //  debug_stream << "Nodes " << e.first << " and " << e.second << endl;
 
  //  copy(owners.begin(), owners.end(), ostream_iterator<Neighbor>(debug_stream, " "));
 
  //  debug_stream << endl;
 

	
 
  // the duplicates in this list indicate cells owning this edge  
 
  list<Neighbor>::iterator c=owners.begin();
 
  while (c!=owners.end()) {
 
    c=adjacent_find(c,owners.end(),  neighbor_cell_eq);
 

	
 

	
 
    if (c!=owners.end()) { // else break;
 

	
 
      //      debug_stream << "Cell " << c->cell << " owns Edge " << e << endl;
 

	
 
 
 
      // find the position of the edge's first node in cell c...
 
      list<Node *>::iterator ins_pos = find
 
	(c->cell->nodes.begin(),
 
	 c->cell->nodes.end(),
 
	 e.first);
 
      // ... second node comes before or after it ...
 

	
 
      // XXXX probably this test is always false XXXX: No, works okay.
 
      if (*(++ins_pos!=c->cell->nodes.end()?
 
	    ins_pos:c->cell->nodes.begin())!=e.second) {
 
	c->cell->nodes.insert(((ins_pos--)!=c->cell->nodes.begin()?ins_pos:(--c->cell->nodes.end())), new_node);
 
	//cells[c->cell].nodes.insert(--ins_pos, new_node->index);
 
	// .. set the neighbors of the new node ...
 
	// in this case e.second and e.first are inverted
 
	//  cerr << "Inverted\n";
 
	new_node->owners.push_back( Neighbor(c->cell, e.second, e.first ) );
 
      } else {
 
	// insert before second node, so leave ins_pos as it is,
 
	// that is incremented
 
	c->cell->nodes.insert(ins_pos, new_node);	
 
	// .. set the neighbors of the new node ...
 
	// cerr << "Not inverted\n";
 
	new_node->owners.push_back( Neighbor(c->cell, e.first, e.second ) );
 
      }
 

	
 
      // redo the neighbors:
 
      //}
 

	
 

	
 
      // - find cell c among owners of Node e.first
 
      list<Neighbor>::iterator cpos=
 
	find_if( e.first->owners.begin(),
 
		 e.first->owners.end(),
 
		 bind2nd( mem_fun_ref(&Neighbor::CellEquals), c->cell->Index()) );
 

	
 
      // - correct the record
 
      if (cpos->nb1 == e.second) {
 
	cpos->nb1 = new_node;
 
      } else 
 
	if (cpos->nb2 == e.second) {
 
	  cpos->nb2 = new_node;
 
	}
 

	
 
      // - same for Node e.second
 
      cpos=
 
	find_if( e.second->owners.begin(),
 
		 e.second->owners.end(),
 
		 bind2nd( mem_fun_ref(&Neighbor::CellEquals), c->cell->Index()) );
 

	
 
      // - correct the record
 
      if (cpos->nb1 == e.first) {
 
	cpos->nb1 = new_node;
 
      } else 
 
	if (cpos->nb2 == e.first) {
 
	  cpos->nb2 = new_node;
 
	}
 

	
 

	
 
    } else break;
 
    c++; 
 
  }
 

	
 
  // Repair neighborhood lists in a second loop, to make sure all
 
  // `administration' is up to date
 
  while (c!=owners.end()) {
 
    c=adjacent_find(c,owners.end(),  neighbor_cell_eq);
 
    // repair neighborhood lists of cell and Wall lists
 

	
 
    if (!c->cell->BoundaryPolP()) {
 
      c->cell->ConstructNeighborList();
 
    
 
    }
 
    c++;
 
  }
 

	
 
}
 

	
 

	
 
/*
 
  Calculate circumcircle of triangle (x1,y1), (x2,y2), (x3,y3)
 
  The circumcircle centre is returned in (xc,yc) and the radius in r
 
  NOTE: A point on the edge is inside the circumcircle
 
*/
 
void Mesh::CircumCircle(double x1,double y1,double x2,double y2,double x3,double y3,
 
			double *xc,double *yc,double *r)
 
{
 
  double m1,m2,mx1,mx2,my1,my2;
 
  double dx,dy,rsqr;
 

	
 
  /* Check for coincident points */
 
  /*if (abs(y1-y2) < TINY && abs(y2-y3) < TINY)
 
    return(false);*/
 

	
 
  if (abs(y2-y1) < TINY) {
 
    m2 = - (x3-x2) / (y3-y2);
 
    mx2 = (x2 + x3) / 2.0;
 
    my2 = (y2 + y3) / 2.0;
 
    *xc = (x2 + x1) / 2.0;
 
    *yc = m2 * (*xc - mx2) + my2;
 
  } else if (abs(y3-y2) < TINY) {
 
    m1 = - (x2-x1) / (y2-y1);
 
    mx1 = (x1 + x2) / 2.0;
 
    my1 = (y1 + y2) / 2.0;
 
    *xc = (x3 + x2) / 2.0;
 
    *yc = m1 * (*xc - mx1) + my1;
 
  } else {
 
    m1 = - (x2-x1) / (y2-y1);
 
    m2 = - (x3-x2) / (y3-y2);
 
    mx1 = (x1 + x2) / 2.0;
 
    mx2 = (x2 + x3) / 2.0;
 
    my1 = (y1 + y2) / 2.0;
 
    my2 = (y2 + y3) / 2.0;
 
    *xc = (m1 * mx1 - m2 * mx2 + my2 - my1) / (m1 - m2);
 
    *yc = m1 * (*xc - mx1) + my1;
 
  }
 

	
 
  dx = x2 - *xc;
 
  dy = y2 - *yc;
 
  rsqr = dx*dx + dy*dy;
 
  *r = sqrt(rsqr);
 

	
 
  return;
 
  // Suggested
 
  // return((drsqr <= rsqr + EPSILON) ? TRUE : FALSE);
 
}
 

	
 
//
 

	
 
// return the total amount of chemical "ch" in the leaf
 
double Mesh::SumChemical(int ch) {
 

	
 
  double sum=0.;
 
  for (vector<Cell *>::iterator i=cells.begin(); i!=cells.end(); i++) {
 
    sum+=(*i)->chem[ch];
 
  }
 
  return sum;
 
}
 

	
 

	
 

	
 
void Mesh::CleanUpCellNodeLists(void) {
 

	
 
  typedef vector <vector<Cell *>::iterator> CellItVect;
 

	
 
  CellItVect cellstoberemoved;
 
  vector<int> cellind;
 

	
 
  // Start of by removing all stale walls.
 
  //DeleteLooseWalls();
 
  // collect all dead cells that need to be removed from the simulation
 
  for (vector<Cell *>::iterator i=cells.begin(); i!=cells.end(); i++) {
 
    if ((*i)->DeadP()) {
 
      // collect the iterators
 
      cellstoberemoved.push_back(i);
 

	
 
      // collect the indices
 
      cellind.push_back((*i)->index);
 
    } else {
 
      // Remove pointers to dead Walls
 
      for (list<Wall *>::iterator w=(*i)->walls.begin(); w!=(*i)->walls.end(); w++) {
 
	if ((*w)->DeadP()) {
 
	  (*w)=0;
 
	}
 
      }
 
      (*i)->walls.remove(0);
 
    }
 
  }
 

	
 
  // Remove pointers to dead Walls from BoundaryPolygon
 
  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);
 

	
 

	
 
  // Renumber cells; this is most efficient if the list of dead cell indices is sorted
 
  sort(cellind.begin(),cellind.end());
 

	
 

	
 
  // Reindexing of Cells
 
  for (vector<int>::reverse_iterator j=cellind.rbegin(); j!=cellind.rend(); j++) {
 
    for (vector<Cell *>::reverse_iterator i=cells.rbegin(); i!=cells.rend(); i++) {
 
      if (*j < (*i)->index) (*i)->index--;
 
    }
 
  }
 

	
 

	
 
  // Actual deleting of Cells
 
  // We must delete in reverse order, otherwise the iterators become redefined
 
  for ( CellItVect::reverse_iterator i=cellstoberemoved.rbegin(); i!=cellstoberemoved.rend(); i++) {
 
    Cell::NCells()--;
 
    cells.erase(*i);
 
  }
 

	
 

	
 
  // same for nodes
 
  typedef vector <vector<Node *>::iterator> NodeItVect;
 

	
 
  NodeItVect nodestoberemoved;
 
  vector<int> nodeindlist;
 

	
 
  // collect iterators and indices of dead nodes
 
  for (vector<Node *>::iterator i=nodes.begin(); i!=nodes.end(); i++) {
 
    if ((*i)->DeadP()) {
 
      nodestoberemoved.push_back( i );
 
      nodeindlist.push_back((*i)->index);
 
    }
 
  }
 

	
 
  // sort the list of dead nodes for renumbering
 
  sort(nodeindlist.begin(),nodeindlist.end());
 

	
 

	
 
  // Reindicing of Nodes
 
  for (vector<int>::reverse_iterator j=nodeindlist.rbegin(); j!=nodeindlist.rend(); j++) {
 
    for (vector<Node *>::reverse_iterator i=nodes.rbegin(); i!=nodes.rend(); i++) {
 
      if (*j < (*i)->index) { 
 
	(*i)->index--;
 
      } 
 
    }
 
  }
 

	
 
  // Actual deleting of nodes
 
  // We must delete in reverse order, otherwise the iterators become redefined
 
  for ( NodeItVect::reverse_iterator i=nodestoberemoved.rbegin(); i!=nodestoberemoved.rend(); i++) {
 
    Node::nnodes--;
 
    nodes.erase(*i);
 
  }
 

	
 

	
 

	
 
  for (list<Wall *>::iterator w=walls.begin(); w!=walls.end(); w++) {
 
    if ((*w)->DeadP()) {
 
      Wall::nwalls--;
 
      delete *w;
 
      *w = 0;
 
    }
 
  }
 

	
 
  walls.remove( 0 );
 

	
 

	
 

	
 
  // Clean up all intercellular connections and redo everything
 
  for (vector<Node *>::iterator i=nodes.begin(); i!=nodes.end(); i++) {
 
    (*i)->owners.clear();
 
  }
 

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

	
 
  boundary_polygon->ConstructConnections();
 

	
 
  // remake shuffled_nodes and shuffled cells
 
  shuffled_nodes.clear();
 
  shuffled_nodes = nodes;
 

	
 
  shuffled_cells.clear();
 
  shuffled_cells = cells;
 
}
 

	
 
void Mesh::CutAwayBelowLine( Vector startpoint, Vector endpoint) {
 

	
 
  // Kills all cells below the line startpoint -> endpoint
 

	
 
  Vector perp = (endpoint-startpoint).Perp2D().Normalised();
 

	
 
#ifdef QDEBUG
 
  qDebug() << "Before Apoptose" << endl;
 
#endif
 

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

	
 
    // do some vector geometry to check whether the cell is below the cutting line
 
    Vector cellvec = ((*i)->Centroid()-startpoint);
 

	
 
    if ( InnerProduct(perp, cellvec) < 0 ) {
 
      // remove those cells
 
      (*i)->Apoptose();
 
    }
 
  }
 

	
 
#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
 
      cerr << "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 = 0;
 
  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);
 

	
 
    //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.
 
*/
 
void Mesh::DeleteLooseWalls(void) {
 

	
 
  list<Wall *>::iterator w=walls.begin();
 

	
 
  while (w!=walls.end()) {
 

	
 
    // if both cells of the wall are dead, remove the wall
 
    if ((*w)->C1()->DeadP() || (*w)->C2()->DeadP()) {
 
      if ((*w)->C1()->DeadP() && (*w)->C2()->DeadP()) {
 
	delete *w;
 
	w=walls.erase(w);
 
      } else {
 
	if ((*w)->C1()->DeadP())
 
	  (*w)->c1 = boundary_polygon;
 
	else
 
	  (*w)->c2 = boundary_polygon;
 
	w++;
 
      }
 
    } else {
 
      w++;
 
    }
 

	
 
  }
 
}
 

	
 
/*void Mesh::FitLeafToCanvas(double width, double height) {
 

	
 
  Vector bbll,bbur;
 
  BoundingBox(bbll,bbur);
 

	
 
  double scale_x = width/(bbur.x-bbll.x);
 
  double scale_y = height/(bbur.y-bbll.y);
 

	
 
  double factor = scale_x<scale_y ? scale_x:scale_y;
 

	
 
  Cell::SetMagnification(factor); // smallest of scale_x and scale_y
 

	
 
  double offset_x = (width/Cell::Magnification()-(bbur.x-bbll.x))/2.;  
 
  double offset_y = (height/Cell::Magnification()-(bbur.y-bbll.y))/2.;
 

	
 
  Cell::setOffset(offset_x, offset_y);
 

	
 
  }*/
 

	
 

	
 

	
 
void Mesh::CleanChemicals(const vector<double> &clean_chem) {
 

	
 
  if (clean_chem.size()!=(unsigned)Cell::NChem()) {
 
    throw "Run time error in Mesh::CleanChemicals: size of clean_chem should be equal to Cell::NChem()";
 
  }
 
  for (vector<Cell *>::iterator c=cells.begin(); c!=cells.end(); c++) {
 
    for (int i=0;i<Cell::NChem();i++) {
 
      (*c)->SetChemical(i,clean_chem[i]);
 
    }
 
    (*c)->SetNewChemToChem();
 
  }
 
}
 

	
 

	
 
void Mesh::CleanTransporters(const vector<double> &clean_transporters) {
 

	
 
  if (clean_transporters.size()!=(unsigned)Cell::NChem()) {
 
    throw "Run time error in Mesh::CleanTransporters: size ofclean_transporters should be equal to Cell::NChem()";
 
  }
 

	
 

	
 
  // clean transporters
 
  for (list<Wall *>::iterator w=walls.begin(); w!=walls.end(); w++) {
 
    for (int i=0;i<Cell::NChem();i++) {
 
      (*w)->setTransporters1(i,clean_transporters[i]); (*w)->setNewTransporters1(i,clean_transporters[i]);
 
      (*w)->setTransporters2(i,clean_transporters[i]); (*w)->setNewTransporters2(i,clean_transporters[i]);
 
    }
 
  }
 
}
 

	
 

	
 
void Mesh::RandomizeChemicals(const vector<double> &max_chem, const vector<double> &max_transporters) {
 

	
 
  if (max_chem.size()!=(unsigned)Cell::NChem() || max_transporters.size()!=(unsigned)Cell::NChem()) {
 
    throw "Run time error in Mesh::CleanChemicals: size of max_chem and max_transporters should be equal to Cell::NChem()";
 
  }
 

	
 
  for (vector<Cell *>::iterator c=cells.begin(); c!=cells.end(); c++) {
 
    for (int i=0;i<Cell::NChem();i++) {
 
      (*c)->SetChemical(i,max_chem[i]*RANDOM());
 
    }
 
    (*c)->SetNewChemToChem();
 
  }
 

	
 
  // randomize transporters
 
  for (list<Wall *>::iterator w=walls.begin(); w!=walls.end(); w++) {
 
    for (int i=0;i<Cell::NChem();i++) {
 
      (*w)->setTransporters1(i,max_transporters[i] * RANDOM()); (*w)->setNewTransporters1(i, (*w)->Transporters1(i) );
 
      (*w)->setTransporters2(i,max_transporters[i] * RANDOM()); (*w)->setNewTransporters2(i, (*w)->Transporters1(i) );
 
    }
 
  }
 
}
 

	
 
//!\brief Calculates a vector with derivatives of all variables, which
 
// we can pass to an ODESolver. 
 
void Mesh::Derivatives(double *derivs) {
 

	
 
  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;
 

	
 
  //static double *derivs = 0; 
 
  // derivs is allocated by RungeKutta class.
 

	
 
  for (int i=0;i<neqs;i++) {
 
    derivs[i]=0.;
 
  }
 

	
 
  // Layout of derivatives: cells [ chem1 ... chem n]  walls [ [ w1(chem 1) ... w1(chem n) ] [ w2(chem 1) ... w2(chem n) ] ]
 

	
 
  int i=0;
 

	
 
  for (vector<Cell *>::iterator c=cells.begin(); c!=cells.end(); c++) {
 
    plugin->CellDynamics(*c, &(derivs[i]));
 
    i+=nchems;
 
  }
 

	
 
  for (list<Wall *>::iterator w=walls.begin(); w!=walls.end(); w++) {
 
    // (*wr)(*w, &(derivs[i]), &(derivs[i+nchems]));
 
    plugin->WallDynamics(*w,  &(derivs[i]), &(derivs[i+nchems]));
 
    // Transport function adds to derivatives of cell chemicals
 
    double *dchem_c1 = &(derivs[(*w)->c1->Index() * nchems]);
 
    double *dchem_c2 = &(derivs[(*w)->c2->Index() * nchems]);
 
    //plugin->CelltoCellTransport(*w, &(derivs[(*w)->c1->Index() * nchems]),
 
    //	  &(derivs[(*w)->c2->Index() * nchems]));
 
    // quick fix: dummy values to prevent end user from writing into outer space and causing a crash :-)
 
    // start here if you want to implement chemical input/output into environment over boundaries
 
    double dummy1, dummy2;
 
    if ((*w)->c1->Index()<0) { // tests if c1 is the boundary pol
 
      dchem_c1 = &dummy1;
 
    }
 
    if ((*w)->c2->Index()<0) {
 
      dchem_c2 = &dummy2;
 
    }
 
    plugin->CelltoCellTransport(*w, dchem_c1, dchem_c2); 
 

	
 
    //(*tf)(*w, &(derivs[(*w)->c1->Index() * nchems]),
 
    //&(derivs[(*w)->c2->Index() * nchems] ) );
 
    i+=2*nchems;
 
  }
 
}
 

	
 
void Mesh::setValues(double x, double *y) {
 

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

	
 
  // Layout of derivatives: cells [ chem1 ... chem n]  walls [ [ w1(chem 1) ... w1(chem n) ] [ w2(chem 1) ... w2(chem n) ] ]
 

	
 
  int i=0;
 
  static int emit_count=0;
 
  const int stride = 100;
 
  for (vector<Cell *>::iterator c=cells.begin(); c!=cells.end(); c++) {
 
    for (int ch=0;ch<nchems;ch++) {
 
      (*c)->SetChemical(ch, y[i+ch]);
 
    }
 
    if ( !(emit_count%stride)) {
 
      (*c)->EmitValues(x);
 
    }
 
    i+=nchems;
 
  }
 

	
 
  for (list<Wall *>::iterator w=walls.begin(); w!=walls.end(); w++) {
 
    for (int ch=0;ch<nchems;ch++) {
 
      (*w)->setTransporters1(ch,y[i+ch]);
 
    }
 
    i+=nchems;
 

	
 
    for (int ch=0;ch<nchems;ch++) {
 
      (*w)->setTransporters2(ch,y[i+ch]);
 
    }
 
    i+=nchems;
 
  }
 
  emit_count++;
 
}
 

	
 
double *Mesh::getValues(int *neqs) {
 

	
 
  int nwalls = walls.size();
 
  int ncells = cells.size();
 
  int nchems = Cell::NChem();
 

	
 
  // two eqs per chemical for each wall, 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.
 
  (*neqs) = 2 * nwalls * nchems + ncells * nchems;
 

	
 
  // Layout of derivatives: cells [ chem1 ... chem n]  walls [ [ w1(chem 1) ... w1(chem n) ] [ w2(chem 1) ... w2(chem n) ] ]
 

	
 
  static double *values = 0;
 
  if (values!=0) { delete[] values; }
 

	
 
  values = new double[*neqs];
 

	
 
  int i=0;
 
  for (vector<Cell *>::iterator c=cells.begin(); c!=cells.end(); c++) {
 
    for (int ch=0;ch<nchems;ch++) {
 
      values[i+ch]=(*c)->Chemical(ch);
 
    }
 
    i+=nchems;
 
  }
 

	
 
  for (list<Wall *>::iterator w=walls.begin(); w!=walls.end(); w++) {
 
    for (int ch=0;ch<nchems;ch++) {
 
      values[i+ch]=(*w)->Transporters1(ch);
 
    }
 
    i+=nchems;
 

	
 
    for (int ch=0;ch<nchems;ch++) {
 
      values[i+ch]=(*w)->Transporters2(ch);
 
    }
 
    i+=nchems;
 
  }
 
  return values;
 
}
 

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

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

	
 
    NodeItem *item = new NodeItem ( &(*i), c );
 
    item->setColor();
 

	
 
    item->setZValue(5);
 
    item->show();
 
    item ->setPos(((Cell::offset[0]+i->x)*Cell::factor),
 
		  ((Cell::offset[1]+i->y)*Cell::factor) );
 
  }
 
}
 

	
 
/*! Returns the sum of protein "ch" of a cycling protein in cells and walls */
 
double Mesh::CalcProtCellsWalls(int ch) const {
 

	
 

	
 
  double sum_prot=0.;
 

	
 
  // At membranes
 
  for (list<Wall *>::const_iterator w=walls.begin(); w!=walls.end(); w++) {
 
    sum_prot += (*w)->Transporters1(ch);
 
    sum_prot += (*w)->Transporters2(ch);
 
  }
 

	
 
  // At cells
 
  for (vector<Cell *>::const_iterator c=cells.begin(); c!=cells.end(); c++) {
 
    sum_prot += (*c)->Chemical(ch);
 
  }
 
  return sum_prot;
 
}
 

	
 
void Mesh::SettoInitVals(void) {
 

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

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

	
 
  CleanChemicals(clean_chem);
 
  CleanTransporters(clean_transporters);
 
}
 

	
 
string Mesh::getTimeHours(void) const {
 
  int hours = (int)(time / 3600);
 
  int mins = (int)((time - hours * 3600)/60);
 
  int secs = (int)((time - hours * 3600 - mins * 60));
 
  ostringstream tstr;
 
  tstr << hours << " h " << mins << " m " << secs << " s";
 
  return tstr.str();
 
}
 

	
 
QVector<qreal> Mesh::VertexAngles(void) {
 
  QVector<qreal> angles;
 
  for (vector<Node *>::const_iterator n=nodes.begin(); n!=nodes.end(); n++) {
 
    if ((*n)->Value()>2 && !(*n)->BoundaryP() ) {
 
      angles+=(*n)->NeighbourAngles();
 
    }
 
  }
 
  return angles;
 
}
 

	
 
QVector< QPair<qreal,int> > Mesh::VertexAnglesValues(void) {
 

	
 
  QVector< QPair<qreal,int> > anglesvalues;
 
  for (vector<Node *>::const_iterator n=nodes.begin(); n!=nodes.end(); n++) {
 
    if ((*n)->Value()>2 && !(*n)->BoundaryP() ) {
 
      QVector<qreal> angles = (*n)->NeighbourAngles();
 
      int value_vertex = angles.size();
 
      for (QVector<qreal>::ConstIterator i=angles.begin(); i!=angles.end(); i++) {
 
	anglesvalues += QPair< qreal, int > (*i, value_vertex);
 
      }
 
    }
 
  }
 
  return anglesvalues;
 
}
 

	
 
void Mesh::Clean(void) {
 
#ifdef QDEBUG
 
  qDebug() << "Freeing nodes" << endl;
 
#endif
 
  for (vector<Node *>::iterator i=nodes.begin(); i!=nodes.end(); i++) {
 
    delete *i;
 
  }
 
  nodes.clear();
 
  Node::nnodes=0;
 

	
 
#ifdef QDEBUG
 
  qDebug() << "Freeing node sets" << endl;
 
#endif
 
  for (vector<NodeSet *>::iterator i=node_sets.begin(); i!=node_sets.end(); i++) {
 
    delete *i;
 
  }
 
  node_sets.clear();
 

	
 

	
 
#ifdef QDEBUG
 
  qDebug() << "Freeing cells" << endl;
 
#endif	
 
  //CellsStaticDatamembers *old_static_data_mem = Cell::GetStaticDataMemberPointer();
 
  for (vector<Cell *>::iterator i=cells.begin(); i!=cells.end(); i++) {
 
    delete *i;
 
  }
 
  //Cell::static_data_members = old_static_data_mem;
 

	
 
  cells.clear();
 
  Cell::NCells()=0;
 

	
 
  if (boundary_polygon) {
 
    delete boundary_polygon; // (already deleted during cleaning of cells?)
 
    boundary_polygon=0;
 
  }
 
#ifdef QDEBUG
 
  qDebug() << "Freeing walls" << endl;
 
#endif
 
  for (list<Wall *>::iterator i=walls.begin(); i!=walls.end(); i++) {
 
    delete *i;
 
  }
 
  walls.clear();
 
  Wall::nwalls=0;
 

	
 
  node_insertion_queue.clear();
 
  shuffled_nodes.clear();
 
  shuffled_cells.clear();
 
  time = 0.0;
 
}
 

	
 
void Mesh::StandardInit(void) {
 

	
 
  boundary_polygon = new BoundaryPolygon();
 
  Cell &circle=CircularCell(0,0,10,10);
 

	
 
  circle.SetTargetArea(circle.CalcArea());
 
  circle.SetTargetLength(par.target_length);
 
  circle.SetLambdaLength(par.lambda_celllength);
 
  SetBaseArea();
 
  // clean up chemicals 
 
  for (int c=0; c<Cell::NChem(); c++) {
 
    circle.SetChemical(c, 0.);
 
  }
 
}
 

	
 
#include "hull.h"
 

	
 
double Mesh::Compactness(double *res_compactness, double *res_area, double *res_cell_area) {
 

	
 
double Mesh::Compactness(double *res_compactness, double *res_area, double *res_cell_area, double *res_circumference) {
 
  
 
  // Calculate compactness using the convex hull of the cells
 
  // We use Andrew's Monotone Chain Algorithm (see hull.cpp)
 

	
 
  // Step 1. Prepare data for 2D hull code - get boundary polygon
 
  int pc=0;
 
  Point *p=new Point[boundary_polygon->nodes.size()];
 
  Point *p=new Point[boundary_polygon->nodes.size()+1];
 
  for (list<Node *>::const_iterator i = boundary_polygon->nodes.begin(); 
 
       i!=boundary_polygon->nodes.end(); i++) {
 
    p[pc++]=Point((*i)->x,(*i)->y);
 
  }
 
  
 
  // chainHull algorithm requires sorted points
 
  qSort( p, p+pc );
 

	
 
 
 
  // Step 2: call 2D Hull code
 
  int np=boundary_polygon->nodes.size();
 
  Point *hull=new Point[np];
 
  Point *hull=new Point[np+1];
 
  int nph=chainHull_2D(p,np,hull);
 
  
 
  
 
  // Step 3: calculate area of convex hull
 
  // Step 3: calculate area and circumference of convex hull
 
  double hull_area=0.;
 
  double hull_circumference=0.;
 

	
 
  for (int i=0;i<nph-1;i++) {
 
    hull_area+=hull[i].x * hull[i+1].y - hull[i+1].x * hull[i].y;
 
    double s_dx=(hull[i+1].x-hull[i].x);
 
    double s_dy=(hull[i+1].y-hull[i].y);
 
    double l=sqrt(s_dx*s_dx+s_dy*s_dy);
 
    //    f << hull[i].x << " " << hull[i].y << " " << hull[i+1].x << " " << hull[i+1].y << " " << l << endl;
 
    hull_circumference+=l;
 
      
 
  }
 
  hull_area/=2.;
 

	
 
  // Step 4: get area of bounary polygon
 
  double boundary_pol_area = boundary_polygon->CalcArea();
 
  
 

	
 
  /*  ofstream datastr("hull.dat");
 
  for (int i=0;i<nph<i++) {
 
    datastr << hull.x << " " << hull.y << endl;
 
  }
 
  ofstream polstr("pol.dat");
 
  for (int i=0;i<np;h*/
 
  delete[] p;
 
  delete[] hull;
 

	
 

	
 
  // put intermediate results into optional pointers
 
  if (res_compactness) {
 
    *res_compactness = boundary_pol_area/hull_area;
 
  }
 
  if (res_area) {
 
    *res_area = hull_area;
 
  }
 
  if (res_cell_area) {
 
    *res_cell_area = boundary_pol_area;
 
  }
 

	
 
  if (res_circumference) {
 
    *res_circumference = hull_circumference;
 
  }
 
  
 
  // return compactness
 
  return boundary_pol_area/hull_area;
 

	
 
}
 

	
 
// DataExport
 
void Mesh::CSVExportCellData(QTextStream &csv_stream) const {
 

	
 
  csv_stream << "\"Cell Index\",\"Center of mass (x)\",\"Center of mass (y)\",\"Cell area\",\"Cell length\"";
 
  
 
  for (int c=0;c<Cell::NChem(); c++) {
 
    csv_stream << ",\"Chemical " << c << "\"";
 
  }
 
  csv_stream << endl;
 
  for (vector<Cell *>::const_iterator i=cells.begin();
 
       i!=cells.end();
 
       i++) {
 
    Vector centroid = (*i)->Centroid();
 
    csv_stream << (*i)->Index() << ", "
 
	       << centroid.x << ", "
 
	       << centroid.y << ", " 
 
	       <<  (*i)->Area() << ", "
 
	       <<(*i)->Length();
 
    for (int c=0;c<Cell::NChem(); c++) {
 
      csv_stream << ", " << (*i)->Chemical(c);
 
    }
 
    csv_stream << endl;
 
  }
 
}
 

	
 

	
 
void Mesh::CSVExportMeshData(QTextStream &csv_stream) { 
 
  
 
  csv_stream << "\"Mesh area\",\"Number of cells\",\"Number of nodes\",\"Compactness\",\"Hull area\",\"Cell area\"" << endl;
 
  csv_stream << "\"Morph area\",\"Number of cells\",\"Number of nodes\",\"Compactness\",\"Hull area\",\"Morph circumference\",\"Hull circumference\"" << endl;
 
  
 
  double res_compactness, res_area, res_cell_area;
 
  Compactness(&res_compactness, &res_area, &res_cell_area);
 
  csv_stream << Area() << ", " << NCells() << ", " << NNodes() << ", " << res_compactness << ", " << res_area << ", " << res_cell_area  << endl;
 
  double res_compactness, res_area, res_cell_area, hull_circumference;
 
  Compactness(&res_compactness, &res_area, &res_cell_area, &hull_circumference);
 
  double morph_circumference = boundary_polygon->ExactCircumference();
 
  csv_stream << Area() << ", " << NCells() << ", " << NNodes() << ", " << res_compactness << ", " << res_area << ", " << morph_circumference << ", " << hull_circumference << endl;
 
  
 
}
 
/* 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;
 
  };
 
  ~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 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*);
 

	
 
 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)