Changeset - 9a40ab737a73
[Not reviewed]
default
0 14 2
Roeland Merks - 15 years ago 2010-09-08 17:31:50
merks@cwi.nl
* Added functionality for numerical output (CSV) format. See functions starting with "CSV" in mesh.cpp. External code hull.cpp is responsible for convex hull calculations.
- ToDo: adopt menu item "File->export cell areas" so user can choose a file name or set up periodic output of numerical data.
- ToDo: add parameters re: periodic numeric output to "<settings>" block of LeafML-file, so it becomes possible to set up numeric output interactively, then write the LeafML file and run the program in batch mode to retrieve periodic numeric output.

* Added new functionality to plugin interface. It becomes possible to define a default LeafML init file for a plugin. It is read whenever the model plugin is loaded.
- ToDo: define default LeafML files for all plugins, according to the LeafML files mentioned in the Plant Phys. tutorial.


user: Roeland Merks <merks@cwi.nl>
branch 'default'
added src/hull.cpp
added src/hull.h
changed src/TutorialCode/Tutorial0/tutorial0.pro
changed src/VirtualLeaf.cpp
changed src/VirtualLeaf.pro
changed src/build_models/auxingrowthplugin.cpp
changed src/build_models/auxingrowthplugin.h
changed src/canvas.cpp
changed src/canvas.h
changed src/mainbase.h
changed src/mesh.cpp
changed src/mesh.h
changed src/modelcatalogue.cpp
changed src/simplugin.cpp
changed src/simplugin.h
changed src/xmlwrite.cpp
16 files changed with 340 insertions and 20 deletions:
0 comments (0 inline, 0 general)
src/TutorialCode/Tutorial0/tutorial0.pro
Show inline comments
 
#
 
# $Id$
 
#
 
#  This file is part of the Virtual Leaf.
 
#
 
#  The Virtual Leaf is free software: you can redistribute it and/or modify
 
#  it under the terms of the GNU General Public License as published by
 
#  the Free Software Foundation, either version 3 of the License, or
 
#  (at your option) any later version.
 
#
 
#  The Virtual Leaf is distributed in the hope that it will be useful,
 
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
#  GNU General Public License for more details.
 
#
 
#  You should have received a copy of the GNU General Public License
 
#  along with the Virtual Leaf.  If not, see <http://www.gnu.org/licenses/>.
 
#
 
#  Copyright 2010 Roeland Merks.
 
#
 

	
 

	
 
TARGET = tutorial0
 
VLEAFHOME = ../../..
 

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

	
 
BINDIR = $${VLEAFHOME}/bin
 
LIBDIR = $${VLEAFHOME}/lib
 
INCDIR = $${VLEAFHOME}/src
 
DEFINES = QTGRAPHICS # VLEAFPLUGIN
 
DESTDIR = $${BINDIR}/models
 
HEADERS = $${TARGET}.h 
 
HEADERS = $${TARGET}.h $${INCDIR}/simplugin.h
 
INCLUDEPATH += $${INCDIR}	
 

	
 
QMAKE_CXXFLAGS += -fexceptions #-I$${INCDIR}
 
QMAKE_CXXFLAGS_DEBUG += -g3
 
QMAKE_CXXFLAGS_DEBUG += -DQDEBUG
 
QT += qt3support
 
SOURCES = $${TARGET}.cpp
 
TEMPLATE = lib 
 

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

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

	
 
}
 

	
 
# finish
src/VirtualLeaf.cpp
Show inline comments
 
@@ -133,331 +133,341 @@ public:
 
  }
 
};
 

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

	
 

	
 

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

	
 
    if (leaffile) 
 
      main_window->Init(leaffile);
 

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

	
 
    main_window->FitLeafToCanvas();
 

	
 
    main_window->Plot();
 

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

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

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

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

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

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

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

	
 
!win32 {
 
 GRAPHICS = qt #qwt
 
}
 

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

	
 

	
 
macx:release {
 
 LIBS+= -dead_strip
 
}
 

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

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

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

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

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

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

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

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

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

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

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

	
 

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

	
 

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

	
 

	
 

	
 

	
 
Q_EXPORT_PLUGIN2(auxingrowthplugin, AuxinGrowthPlugin)
 

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

	
 
#ifndef _AUXINGROWTHPLUGIN_H_
 
#define _AUXINGROWTHPLUGIN_H_
 

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

	
 

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

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

	
 
  virtual QString DefaultLeafML(void) { return QString("auxin_growth.xml"); }
 
 
 
 private:
 
  double complex_PijAj(CellBase *here, CellBase *nb, Wall *w);
 
};
 

	
 
#endif
 

	
 
/* finis */
src/canvas.cpp
Show inline comments
 
@@ -384,192 +384,193 @@ void FigureEditor::mouseReleaseEvent(QMo
 

	
 

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

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

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

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

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

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

	
 
  delete intersection_line;
 
  intersection_line = 0;
 
  return colliding_cells;
 
}
 

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

	
 

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

	
 

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

	
 
static uint mainCount = 0;
 

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

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

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

	
 
  Q3PopupMenu* file = new Q3PopupMenu( menu );
 

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

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

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

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

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

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

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

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

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

	
 

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

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

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

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

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

	
 

	
 
  menu->insertSeparator();
 

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

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

	
 
  stopSimulation();
 
  statusBar()->addWidget(new QLabel("Ready."));
 
@@ -1260,97 +1261,111 @@ void Main::CleanMeshChemicals(void)
 
{
 

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

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

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

	
 
  editor->FullRedraw();
 
}
 

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

	
 
  mesh.CleanTransporters(clean_transporters);
 

	
 
  mesh.setTime(0);
 
  Plot();
 

	
 
  editor->FullRedraw();
 
}
 

	
 
void Main::RandomizeMesh(void) 
 
{
 

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

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

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

	
 
  mesh.RandomizeChemicals(max_chem, max_transporters);
 

	
 
  Plot();
 
}
 

	
 
void Main::XMLReadSettings(xmlNode *settings) 
 
{
 

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

	
 
xmlNode *Main::XMLSettingsTree(void) 
 
{
 

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

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

	
 
void Main::exportCellData(void) {
 

	
 
  // perhaps make this more general: a popup window were user selects data he wants to export
 
  // can go to "settings" section of XML file as well so this can also be measured off-line
 
  // mesh.CSVExport would take an QMap or so to record all options
 
  // first line gives legenda
 
  QFile file("areas.csv");
 
  if ( file.open( IO_WriteOnly ) ) {
 
    QTextStream stream( &file );
 
    mesh.CSVExportCellData(stream);
 
    mesh.CSVExportMeshData(stream);
 
    file.close();
 
  }
 
}
 
/* finis */
src/canvas.h
Show inline comments
 
@@ -113,167 +113,168 @@ class Main : public Q3MainWindow, public
 
  virtual bool ShowMeshP(void) {return view->isItemChecked(mesh_id);}
 
  virtual bool ShowBorderCellsP(void) {return view->isItemChecked(border_id);}
 
  virtual bool PausedP(void) {return run->isItemChecked(paused_id);}
 
  virtual bool ShowNodeNumbersP(void) {return view->isItemChecked(node_number_id);}
 
  virtual bool ShowCellNumbersP(void) {return view->isItemChecked(cell_number_id);}
 
  virtual bool ShowCellAxesP(void) {return view->isItemChecked(cell_axes_id);}
 
  virtual bool ShowCellStrainP(void) {return view->isItemChecked(cell_strain_id);}
 
  virtual bool MovieFramesP(void) {return view->isItemChecked(movie_frames_id);}
 
  virtual bool ShowBoundaryOnlyP(void) {return view->isItemChecked(only_boundary_id);}
 
  virtual bool ShowWallsP(void) {return view->isItemChecked(cell_walls_id);}
 
  virtual bool ShowApoplastsP(void) { return view->isItemChecked(apoplasts_id);}
 
  virtual bool ShowFluxesP(void) { return view->isItemChecked(fluxes_id); }
 
  virtual bool DynamicCellsP(void) { return options->isItemChecked(dyn_cells_id); }
 
  virtual bool RotationModeP(void) { return options->isItemChecked(rotation_mode_id); }
 
  virtual bool InsertModeP(void) { return options->isItemChecked(insert_mode_id); }
 
  virtual bool ShowToolTipsP(void) { return helpmenu->isItemChecked(tooltips_id); }
 
  virtual bool HideCellsP(void) { return view->isItemChecked(hide_cells_id); }
 
  void scale(double factor); 
 
  virtual double getFluxArrowsize(void)
 
  {
 
    return flux_arrow_size;
 
  }
 

	
 
  void FitCanvasToWindow();
 
  void FitLeafToCanvas(void);
 

	
 

	
 
  public slots:
 

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

	
 
  void EnterRotationMode(void)
 
  {
 

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

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

	
 
    }
 

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

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

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

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

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

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

	
 
  void RandomizeMesh();
 

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

	
 
 protected:
 
  Mesh &mesh;
 

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

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

	
 
#endif
 

	
 
/* finis*/
src/hull.cpp
Show inline comments
 
new file 100644
 
// 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);
 
}
 
//===================================================================
 
 
 

	
 
// 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
 
new file 100644
 
// 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;
 

	
 
};
 

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

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

	
 

	
 
#ifndef _MAINBASE_H_
 
#define _MAINBASE_H_
 

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

	
 
using namespace std;
 

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

	
 
 public:
 
 MainBase(QGraphicsScene &c, Mesh &m) : mesh(m), canvas(c) {
 

	
 
    // Standard options for batch version
 
    showcentersp =  false;
 
    showmeshp =  false;
 
    showbordercellp =  false;
 
    shownodenumbersp =  false;
 
    showcellnumbersp =  false;
 
    showcellsaxesp = false;
 
    showcellstrainp =  false;
 
    movieframesp = true;
 
    showboundaryonlyp =  false;
 
    showwallsp =  false;
 
    showfluxesp = false;
 
    dynamicscellsp = true;
 
    showtooltipsp = false;
 
    hidecellsp = false;
 
  }
 
  virtual ~MainBase() {};
 

	
 
  virtual double TimeStep();
 
  virtual void Init(char *leaffile=0);
 
  virtual void Init(const char *leaffile=0);
 

	
 
  virtual bool ShowCentersP(void) {return showcentersp;}
 
  virtual bool ShowMeshP(void) {return showmeshp; }
 
  virtual bool ShowBorderCellsP(void) {return showbordercellp; }
 
  virtual bool PausedP(void) {return false; }
 
  virtual bool ShowNodeNumbersP(void) {return shownodenumbersp; }
 
  virtual bool ShowCellNumbersP(void) {return showcellnumbersp;}
 
  virtual bool ShowCellAxesP(void) {return showcellsaxesp;}
 
  virtual bool ShowCellStrainP(void) {return showcellstrainp;}
 
  virtual bool MovieFramesP(void) {return movieframesp;}
 
  virtual bool ShowBoundaryOnlyP(void) {return showboundaryonlyp;}
 
  virtual bool ShowToolTipsP(void) {return showtooltipsp;}
 
  virtual bool ShowWallsP(void) {return showwallsp;}
 
  virtual bool ShowApoplastsP(void) { return showapoplastsp;}
 
  virtual bool ShowFluxesP(void) { return showfluxesp; }
 
  virtual bool DynamicCellsP(void) { return dynamicscellsp; }
 
  virtual void FitCanvasToWindow() {};
 
  virtual void FitLeafToCanvas() {};
 
  virtual bool HideCellsP(void) { return hidecellsp; }
 
  virtual void clear(void) {
 
    QList<QGraphicsItem *> list = canvas.items();
 
    QList<QGraphicsItem *>::Iterator it = list.begin();
 
    for (; it != list.end(); ++it) {
 
      if ( *it )
 
	delete *it;
 
    }
 
  };
 
  virtual void XMLReadSettings(xmlNode *settings);
 
  virtual void XMLReadViewport(xmlNode *viewport);
 

	
 
  virtual double getFluxArrowsize(void) { return 10.;}
 

	
 
  void Save(const char *fname, const char *format, int sizex=640, int sizey=480);
 
  void CutSAM(void);
 

	
 
  void Plot(int resize_stride=10);
 

	
 
  virtual void UserMessage(QString message, int timeout = 0) {
 
    cerr << message.toAscii().constData() << endl;
 
  }
 

	
 
  Mesh &mesh;
 
  QTransform viewport;
 

	
 
 protected:
 
  QGraphicsScene &canvas;
 
  virtual xmlNode *XMLSettingsTree(void) const;
 
  virtual xmlNode *XMLViewportTree(QTransform &transform) const;
 
  
 
 protected:
 
  bool showcentersp;
 
  bool showmeshp;
 
  bool showbordercellp;
 
  bool shownodenumbersp;
 
  bool showcellnumbersp;
 
  bool showcellsaxesp;
 
  bool showcellstrainp;
 
  bool movieframesp;
 
  bool showboundaryonlyp;
 
  bool showwallsp;
 
  bool showapoplastsp;
 
  bool showfluxesp;
 
  bool dynamicscellsp;
 
  bool showtooltipsp;
 
  bool hidecellsp;
 
};
 

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

	
 
#endif
 

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

	
 
#include <string>
 
#include <algorithm>
 
#include <vector>
 
#include <sstream>
 
#include <cstdlib>
 
//#include <cerrno>
 
#include <cstring>
 
#include <numeric>
 
#include <functional>
 
#include <fstream>
 
#include <QPair>
 
#include "mesh.h"
 
#include "tiny.h"
 
#include "parameter.h"
 
#include "random.h"
 
#include "pi.h"
 
#include "parse.h"
 
#include "matrix.h"
 
#include "sqr.h"
 
#include "nodeset.h"
 
#include "nodeitem.h"
 
#include "simplugin.h"
 

	
 
#include <QDebug>
 
#include <set>
 
#include <iostream>
 
#include <iterator>
 
#include <QTextStream>
 

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

	
 
extern Parameter par;
 

	
 
void Mesh::AddNodeToCellAtIndex(Cell *c, Node *n, Node *nb1, Node *nb2, list<Node *>::iterator ins_pos) {
 
  c->nodes.insert(ins_pos, n);        
 
  n->owners.push_back( Neighbor(c, nb1, nb2 ) );
 
}
 

	
 

	
 
void Mesh::AddNodeToCell(Cell *c, Node *n, Node *nb1, Node *nb2) {
 

	
 
  c->nodes.push_back( n );
 
  n->owners.push_back( Neighbor(c, nb1, nb2 ) );
 
}
 

	
 
void Mesh::PerturbChem(int chemnum, double range) {
 

	
 
  for (vector<Cell *>::iterator i=cells.begin(); i!=cells.end(); i++) {
 
    (*i)->chem[chemnum] += range*(RANDOM()-0.5);
 
    if ((*i)->chem[chemnum]<0.) (*i)->chem[chemnum]=0.;
 
  }
 
}
 

	
 
void Mesh::CellFiles(const Vector ll, const Vector ur) {
 

	
 
  Cell *cell = RectangularCell(ll,ur,0.001); 
 

	
 
  for (int c=0;c<Cell::NChem();c++) {
 
    cell->SetChemical(c,par.initval[c]);
 
  }
 

	
 
  cell->SetTargetArea(cell->CalcArea());
 

	
 
  Vector axis(1,0,0);
 

	
 
  // divide rectangle a number of times
 
  for (int i=0;i<6;i++) {
 
    IncreaseCellCapacityIfNecessary();
 

	
 
    vector <Cell *> current_cells = cells;
 
    for (vector<Cell *>::iterator j=current_cells.begin(); j!=current_cells.end();j++) {
 
      (*j)->DivideOverAxis(axis);
 
    }
 
    axis=axis.Perp2D();
 

	
 
  }
 

	
 
  IncreaseCellCapacityIfNecessary();
 

	
 
  axis=axis.Perp2D();
 

	
 
  vector <Cell *> current_cells = cells;
 
  for (vector<Cell *>::iterator j=current_cells.begin(); j!=current_cells.end();j++) {
 
    (*j)->DivideOverAxis(axis);
 
  }
 

	
 

	
 
  double sum_l=0; int n_l=0;
 
  for (list<Node *>::const_iterator i=cell->nodes.begin(); i!=cell->nodes.end(); i++) {
 
    list<Node *>::const_iterator nb=i; nb++; 
 
    if (nb==cell->nodes.end()) 
 
      nb=cell->nodes.begin();
 

	
 
    double l = (**nb-**i).Norm();
 

	
 
    sum_l += l;
 
    n_l++;
 

	
 
  }
 

	
 

	
 
  Node::target_length = sum_l/(double)n_l;
 
  // a bit more tension
 
  Node::target_length/=4.;
 

	
 
  SetBaseArea();
 
}
 

	
 
Cell *Mesh::RectangularCell(const Vector ll, const Vector ur, double rotation) {
 

	
 
  Cell *cell=AddCell(new Cell());
 
  cell->m=this;
 

	
 
  Matrix rotmat;
 
  rotmat.Rot2D(rotation); // rotation over 0,0
 

	
 
  Node *n1=AddNode(new Node(rotmat * ll));
 
  Node *n2=AddNode(new Node(rotmat * Vector(ll.x, ur.y,0)));
 
  Node *n3=AddNode(new Node(rotmat * ur));
 
  Node *n4=AddNode(new Node(rotmat * Vector(ur.x, ll.y,0)));
 

	
 
  n1->boundary=true;
 
  n2->boundary=true;
 
  n3->boundary=true;
 
@@ -374,193 +375,196 @@ Cell &Mesh::LeafPrimordium(int nnodes, d
 

	
 
  circle->setCellVec(Vector(0,1,0));
 

	
 
  return *circle;
 
}
 

	
 
/*Cell &Mesh::Box() {
 
  }*/
 

	
 

	
 
// return bounding box of mesh
 
void Mesh::BoundingBox(Vector &LowerLeft, Vector &UpperRight) {
 

	
 
  LowerLeft = **nodes.begin();
 
  UpperRight = **nodes.begin();
 
  for (vector<Node *>::iterator c=nodes.begin(); c!=nodes.end(); c++) {
 
    if ((*c)->x < LowerLeft.x)
 
      LowerLeft.x = (*c)->x;
 
    if ((*c)->y < LowerLeft.y)
 
      LowerLeft.y = (*c)->y;
 
    if ((*c)->z < LowerLeft.z)
 
      LowerLeft.z = (*c)->z;
 
    if ((*c)->x > UpperRight.x) 
 
      UpperRight.x = (*c)->x;
 
    if ((*c)->y > UpperRight.y) 
 
      UpperRight.y = (*c)->y;
 
    if ((*c)->z > UpperRight.z)
 
      UpperRight.z = (*c)->z;
 
  }
 
}
 

	
 

	
 
double Mesh::Area(void) {
 

	
 
  double area=0;
 
  vector<Cell *>::iterator i=cells.begin();
 
  while (i != cells.end()) {
 
    area += (*(i++))->Area();
 
  }
 
  return area;
 
}
 

	
 
void Mesh::SetBaseArea(void) {
 

	
 
  // Set base area to mean area. 
 
  // This method is typically called during initiation, after
 
  // defining the first cell
 
  Cell::BaseArea() = Area()/cells.size();
 
}
 

	
 
// for optimization, we moved Displace to Mesh
 

	
 
class DeltaIntgrl {
 

	
 
public:
 
  double area;
 
  double ix, iy;
 
  double ixx,ixy,iyy;
 
  DeltaIntgrl(double sarea,double six,double siy,double sixx,double sixy,double siyy) {
 
    area=sarea;
 
    ix=six;
 
    iy=siy;
 
    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;
 

	
 
  delete boundary_polygon;
 
  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();
 
  //Cell::ncells=0;
 
  /*    Cell::ClearNCells();
 
	Node::nnodes=0;
 

	
 
	cells.clear();
 
	nodes.clear();
 
	shuffled_cells.clear();
 
	shuffled_nodes.clear();
 
	node_insertion_queue.empty();
 

	
 
	cerr << "Meshed cleared: cells: " << cells.size() << ", nodes: " << nodes.size() << endl;
 
  */
 

	
 
#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++) {
 

	
 
@@ -1902,129 +1906,224 @@ double Mesh::CalcProtCellsWalls(int ch) 
 

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

	
 
  // Amount of PIN1
 
  //clean_chem[1] = 0.;
 

	
 
  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;
 

	
 
  delete boundary_polygon; // (already deleted during cleaning of cells?)
 

	
 
  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) {
 
  
 
  // 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()];
 
  for (list<Node *>::const_iterator i = boundary_polygon->nodes.begin(); 
 
       i!=boundary_polygon->nodes.end(); i++) {
 
    p[pc++]=Point((*i)->x,(*i)->y);
 
  }
 
  
 
  // Step 2: call 2D Hull code
 
  int np=boundary_polygon->nodes.size();
 
  Point *hull=new Point[np];
 
  int nph=chainHull_2D(p,np,hull);
 
  
 
  
 
  // Step 3: calculate area of convex hull
 
  double hull_area=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;
 
  }
 
  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;
 
  }
 

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

	
 

	
 
// 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) {
 
    delete boundary_polygon;
 
    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) {
 
@@ -287,142 +292,145 @@ class Mesh {
 
      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);
 
  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 */
src/modelcatalogue.cpp
Show inline comments
 
@@ -54,107 +54,151 @@ void ModelCatalogue::LoadPlugins() {
 
  } 
 
  plugin_filters << "*.dylib";
 
#endif 
 
  pluginDir.setNameFilters(plugin_filters);
 

	
 
  if (!pluginDir.cd("models")) {
 
    MyWarning::error("Directory 'models' not found!");
 
  }
 

	
 

	
 
  //QVector<SimPluginInterface *> plugins;
 
  foreach (QString fileName, pluginDir.entryList(QDir::Files)){ 
 
    QPluginLoader loader(pluginDir.absoluteFilePath(fileName)); 
 
    if (SimPluginInterface *plugin = 
 
	qobject_cast<SimPluginInterface *>(loader.instance())) {
 
      models.append(plugin); 
 
    } else {
 
      cerr << loader.errorString().toStdString().c_str() << endl;
 
      MyWarning::warning("Could not load model %s: %s",fileName.toStdString().c_str(), loader.errorString().toStdString().c_str());
 
    }
 
  }
 
  if (models.size()==0) {
 
    MyWarning::error("No models could be loaded.");
 
  }
 
}
 

	
 
void ModelCatalogue::LoadPlugin(const char *model) {
 

	
 

	
 
  QDir pluginDir(QApplication::applicationDirPath()); 
 
  QStringList plugin_filters; // filter for plugins, i.e "*.dll", "*.dylib"
 

	
 

	
 
#if defined(Q_OS_WIN) 
 
  if (pluginDir.dirName().toLower() =="debug" 
 
      ||pluginDir.dirName().toLower() =="release") 
 
    pluginDir.cdUp(); 
 
  //plugin_filters << "*.dll";
 
#elif defined(Q_OS_MAC) 
 
  if (pluginDir.dirName() =="MacOS"){ 
 
    pluginDir.cdUp(); 
 
    pluginDir.cdUp(); 
 
    pluginDir.cdUp(); 
 
  } 
 
  //plugin_filters << "*.dylib";
 
#endif
 
  plugin_filters << model;
 
  pluginDir.setNameFilters(plugin_filters);
 

	
 
  if (!pluginDir.cd("models")) {
 
    MyWarning::error("Directory 'models' not found!");
 
  }
 

	
 
  QStringList modelnames=pluginDir.entryList(QDir::Files);
 
  if (modelnames.empty()) {
 
    MyWarning::error("Model %s not found - hint: do not include path in filename.",model);
 
  }
 
  foreach (QString fileName, modelnames){ 
 
    QPluginLoader loader(pluginDir.absoluteFilePath(fileName)); 
 

	
 
    if (SimPluginInterface *plugin = 
 
	qobject_cast<SimPluginInterface *>(loader.instance())) {
 
      models.append(plugin); 
 
      //MyWarning::warning("Successfully loaded model %s",fileName.toStdString().c_str());
 
    } else {
 
      MyWarning::warning("Could not load plugin %s",fileName.toStdString().c_str());
 
    }
 
  }
 
}
 

	
 
void ModelCatalogue::InstallFirstModel() {
 
  InstallModel(models[0]);
 
}
 
void ModelCatalogue::PopulateModelMenu() {
 
  foreach (SimPluginInterface *model, models) {
 
    QAction *modelaction = new QAction(model->ModelID(), mainwin); 
 
    QVariant data;
 
    data.setValue(model);
 
    modelaction->setData(data);
 
    mainwin->modelmenu->addAction(modelaction);
 

	
 
  }
 
  connect(mainwin->modelmenu, SIGNAL(triggered(QAction *)), this, SLOT(InstallModel(QAction *)) );
 
}	
 

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

	
 
void ModelCatalogue::InstallModel(SimPluginInterface *plugin) {
 

	
 
  // make sure both main and plugin use the same static datamembers (ncells, nchems...)
 
  mesh->Clean();
 
  plugin->SetCellsStaticDatamembers(CellBase::GetStaticDataMemberPointer());
 

	
 
  mesh->SetSimPlugin(plugin);
 
 
 

	
 
  Cell::SetNChem(plugin->NChem());
 
  plugin->SetParameters(&par);
 

	
 
  
 
  if (mainwin) {
 
    mainwin->RefreshInfoBar();
 
    mainwin->Init(0);
 
    if (plugin->DefaultLeafML().isEmpty()) {
 
      mainwin->Init(0);
 
    } else {
 
      // locate LeafML file
 
      
 
      QDir pluginDir(QApplication::applicationDirPath()); 
 
      QStringList plugin_filters; // filter for plugins, i.e "*.dll", "*.dylib"
 
      
 
      
 
#if defined(Q_OS_WIN) 
 
      if (pluginDir.dirName().toLower() =="debug" 
 
	  ||pluginDir.dirName().toLower() =="release") 
 
	pluginDir.cdUp(); 
 
      //plugin_filters << "*.dll";
 
#elif defined(Q_OS_MAC) 
 
      if (pluginDir.dirName() =="MacOS"){ 
 
	pluginDir.cdUp(); 
 
	pluginDir.cdUp(); 
 
	pluginDir.cdUp(); 
 
      }
 
     
 
#endif
 
       // for all OS-es. Move from "bin" directory to root application folder.
 
      pluginDir.cdUp();
 
      cerr << "pluginDir: " << pluginDir.dirName().toStdString().c_str() << endl;
 
      if (!pluginDir.cd("data/leaves")) {
 
	MyWarning::warning("Directory 'data/leaves' not found! Cannot load LeafML file '%s'. Reverting to standard initial condition now...",plugin->DefaultLeafML().toStdString().c_str());
 
	mainwin->Init(0);
 
      } else {
 
      
 
	if (!pluginDir.exists(plugin->DefaultLeafML())) {
 
	  MyWarning::error("LeafML file '%s' not found - hint: is file in data/leaves folder? Reverting to standard initial condition now...",plugin->DefaultLeafML().toStdString().c_str());
 
	  mainwin->Init(0); 
 
	} else {
 
	  // Initialize simulation using default LeafML file referenced in plugin.
 
	  //mainwin->Init(0);
 
	  cerr << "Default LeafML: " << plugin->DefaultLeafML().toStdString().c_str() << endl;
 
	  mainwin->Init(pluginDir.absFilePath(plugin->DefaultLeafML()).toStdString().c_str());
 
	}
 
      }
 
    }
 
  }
 

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

	
 
#include <string>
 
#include <QString>
 
#include "simplugin.h"
 

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

	
 
void SimPluginInterface::SetParameters(Parameter *pass_pars)
 
{
 
  par = pass_pars; 
 
}
 

	
 
void SimPluginInterface::SetCellsStaticDatamembers( CellsStaticDatamembers *cells_static_data_members_of_main)
 
{
 
  CellBase::static_data_members = cells_static_data_members_of_main;
 
}
 

	
 
QString SimPluginInterface::DefaultLeafML(void) { return QString(); }
 

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

	
 

	
 
#ifndef _SIMPLUGIN_H_
 
#define _SIMPLUGIN_H_
 

	
 
#include <QtPlugin>
 
#include <QMetaType>
 
#include "cellbase.h"
 
#include "wallbase.h"
 

	
 
class Parameter;
 

	
 
#include <QColor>
 
#include <QString>
 

	
 

	
 
class SimPluginInterface {
 

	
 
 public:
 
  virtual QString ModelID(void) = 0; 
 

	
 
  virtual ~SimPluginInterface() { }
 

	
 
  // Executed after the cellular mechanics steps have equillibrized
 
  virtual void CellHouseKeeping(CellBase *c) = 0;
 

	
 
  // Differential equations describing transport of chemicals from cell to cell
 
  virtual void CelltoCellTransport(Wall *, double *dchem_c1, double *dchem_c2) = 0;
 

	
 
  // Differential equations describing chemical reactions taking place at or near the cell walls
 
  // (e.g. PIN accumulation)
 
  virtual void WallDynamics(Wall *w, double *dw1, double *dw)  = 0;
 

	
 
  // Differential equations describing chemical reactions inside the cells
 
  virtual void CellDynamics(CellBase *c, double *dchem) = 0;
 

	
 
  // to be executed after a cell division
 
  virtual void OnDivide(ParentInfo *parent_info, CellBase *daughter1, CellBase *daughter2) = 0;
 

	
 
  // to be executed for coloring a cell
 
  virtual void SetCellColor(CellBase *c, QColor *color) = 0;
 

	
 
  // Number of chemicals
 
  virtual int NChem(void) = 0;
 

	
 
  // Default LeafML-file to be read after model startup
 
  virtual QString DefaultLeafML(void);
 
  
 
  // For internal use; not to be redefined by end users
 
  virtual void SetParameters(Parameter *pass_pars);// { par = pass_pars; }
 
  virtual void SetCellsStaticDatamembers (CellsStaticDatamembers *cells_static_data_members_of_main);
 

	
 
 protected:
 
  class Parameter *par;
 
};
 

	
 
Q_DECLARE_INTERFACE(SimPluginInterface, "nl.cwi.VirtualLeaf.SimPluginInterface/1.2") 
 
Q_DECLARE_INTERFACE(SimPluginInterface, "nl.cwi.VirtualLeaf.SimPluginInterface/1.3") 
 
Q_DECLARE_METATYPE(SimPluginInterface *)
 

	
 
#endif
 

	
 
/* finis */
src/xmlwrite.cpp
Show inline comments
 
@@ -1353,193 +1353,196 @@ void Mesh::XMLReadWallsToCells(xmlNode *
 
	n = n->next;
 
      }
 

	
 
      if (!xmlStrcmp(cur->name, (const xmlChar *)"boundary_polygon")) {
 

	
 
	int nwalls = tmp_walls_ind.size();
 
	for (int i=0;i<nwalls;i++) {
 
	  boundary_polygon->walls.push_back((*tmp_walls)[tmp_walls_ind[i]]);
 
	}
 
      } else {
 

	
 
	int nwalls = tmp_walls_ind.size();
 
	for (int i=0;i<nwalls;i++) {
 
	  cells[ci]->walls.push_back((*tmp_walls)[tmp_walls_ind[i]]);	
 
	}
 
	ci++;
 
      }
 
    } 
 
    cur=cur->next;
 
  }
 
}
 

	
 

	
 
void Mesh::XMLReadNodeSetsToNodes(xmlNode *root)
 
{
 

	
 
  xmlNode *cur = root->xmlChildrenNode;
 
  int ci=0; // cell index
 

	
 
  while (cur!=NULL) {
 

	
 

	
 

	
 
    if ((!xmlStrcmp(cur->name, (const xmlChar *)"node"))) {
 

	
 
      xmlNode *n = cur->xmlChildrenNode;
 

	
 
      while(n!=NULL) {
 

	
 
	xmlChar *nc = xmlGetProp(n, BAD_CAST "nodeset");
 

	
 
	if (nc!=0) {
 
	  int nodeset_n = atoi( (char *)nc);
 
	  nodes[ci]->node_set = node_sets[nodeset_n];
 
	  xmlFree(nc);
 
	} else {
 
	  nodes[ci]->node_set = 0;
 
	}
 

	
 
	n = n->next;
 
      }
 
      ci++;
 
    } 
 
    cur=cur->next;
 
  }
 
}
 

	
 

	
 
void Mesh::XMLReadNodeSets(xmlNode *root)
 
{
 

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

	
 
  node_sets.clear();
 

	
 
  xmlNode *cur = root->xmlChildrenNode;
 

	
 
  while (cur!=NULL) {
 

	
 
    NodeSet *new_nodeset=0;
 

	
 
    if ((!xmlStrcmp(cur->name, (const xmlChar *)"nodeset"))){
 
      new_nodeset = new NodeSet();
 
      node_sets.push_back(new_nodeset);
 
    } 
 

	
 
    if (new_nodeset == 0) { 
 
      cur = cur->next;
 
      continue;
 
    }
 
    new_nodeset->XMLRead(cur, this);
 
    cur=cur->next;
 
  }
 
}
 

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

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

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

	
 
  xmlNode *cur = root->xmlChildrenNode;
 

	
 
  while (cur!=NULL) {
 

	
 
    Cell *new_cell=0;
 

	
 
    if ((!xmlStrcmp(cur->name, (const xmlChar *)"cell"))){
 

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

	
 
    if (new_cell == 0) { 
 
      cur = cur->next;
 
      continue;
 
    }
 

	
 
    new_cell->XMLRead(cur);
 
    cur=cur->next;
 
  }
 
}
 

	
 
void Mesh::XMLRead(const char *docname, xmlNode **settings, bool geometry, bool pars, bool simtime)
 
{
 

	
 
  xmlDocPtr doc = xmlParseFile(docname);
 
  if (doc == NULL ) {
 
    throw("Document not parsed successfully.");
 
    return;
 
  }
 

	
 
  xmlNodePtr cur = xmlDocGetRootElement(doc);
 

	
 
  if (cur == NULL) {
 
    throw("Document is empty");
 
    xmlFreeDoc(doc);
 
    return;
 
  }
 

	
 
  if (xmlStrcmp(cur->name, (const xmlChar *) "leaf")) {
 
    throw("XML file of the wrong type, it is not a leaf.");
 
    xmlFreeDoc(doc);
 
    return;
 
  }
 

	
 
  /*Get the root element node */
 
  xmlNode *root_element = xmlDocGetRootElement(doc);
 

	
 
  if (geometry) XMLReadGeometry(root_element);
 
  if (pars) XMLReadPars(root_element);
 
  if (simtime) XMLReadSimtime(root_element);
 

	
 
  // If pointer settings defined, return a copy of the settings tree
 
  if (settings) {
 
    xmlNode *cur = root_element->xmlChildrenNode;
 
    // if settings field is not found, *settings will be returned 0.
 
    *settings = 0;
 
    while (cur!=NULL) {
 
      if ((!xmlStrcmp(cur->name, (const xmlChar *)"settings"))){
 
	*settings = xmlCopyNode(cur,1);
 
      }
 
      cur=cur->next;
 
    }
 
  }
 
  xmlFreeDoc(doc);
 

	
 
  /*
 
   *Free the global variables that may
 
   *have been allocated by the parser.
 
   */
 
  xmlCleanupParser();
 

	
 
  // We're doing this so we can manually delete walls with by adding the 'delete="true"' property
 
  CleanUpCellNodeLists();
 
}
 

	
 

	
 
void Parameter::XMLRead(xmlNode *root)
 
{
 

	
 
  xmlNode *cur = root->xmlChildrenNode;
 
  while (cur!=NULL) {
 
    if ((!xmlStrcmp(cur->name, (const xmlChar *)"parameter"))){
 
      xmlNode *par_node = cur->xmlChildrenNode;
 
      while (par_node!=NULL) {
 
	{
 
	  if (!xmlStrcmp(par_node->name, (const xmlChar *)"par")) {
 
	    xmlChar *namec = xmlGetProp(par_node, BAD_CAST "name");
 
	    xmlChar *valc = xmlGetProp(par_node, BAD_CAST "val");
0 comments (0 inline, 0 general)