Changeset - aaba9e8828d6
[Not reviewed]
default
0 5 0
Roeland Merks - 15 years ago 2010-06-07 15:50:24
roeland.merks@cwi.nl
Added to new menu options: edit->ResetChemicals and edit->ResetTransporters, which allows you to set only the chemicals or only the transporters to the initial values. I needed this for preparing a suitable initial condition for Tutorial 6 and thought it would be useful for the main distribution.

--
user: Roeland Merks <roeland.merks@cwi.nl>
branch 'default'
changed src/build_models/Makefile
changed src/canvas.cpp
changed src/canvas.h
changed src/mesh.cpp
changed src/mesh.h
5 files changed with 315 insertions and 59 deletions:
0 comments (0 inline, 0 general)
src/build_models/Makefile
Show inline comments
 
# $Id: Makefile,v 3f0977faba37 2010/06/03 15:54:37 michael $
 
#############################################################################
 
# Makefile for building: libauxinsimon.so
 
# Generated by qmake (2.01a) (Qt 4.4.1) on: Mon Jun 7 13:36:27 2010
 
# Project:  auxinsimon.pro
 
# Template: lib
 
# Command: /ufs/merks/Trolltech/Qt-4.4.1/bin/qmake -unix -o Makefile auxinsimon.pro
 
#############################################################################
 

	
 
QMAKE = qmake
 
####### Compiler, tools and options
 

	
 
all: plugin_auxingrowth plugin_leaf plugin_meinhardt plugin_test
 
CC            = gcc
 
CXX           = g++
 
DEFINES       = -DQTGRAPHICS -DQT_NO_DEBUG -DQT_PLUGIN -DQT_QT3SUPPORT_LIB -DQT3_SUPPORT -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED
 
CFLAGS        = -m64 -pipe -O2 -Wall -W -D_REENTRANT -fPIC $(DEFINES)
 
CXXFLAGS      = -m64 -pipe -fexceptions -I.. -fPIC -I/usr/include/libxml2 -O2 -Wall -W -D_REENTRANT -fPIC $(DEFINES)
 
INCPATH       = -I../../../../Trolltech/Qt-4.4.1/mkspecs/linux-g++-64 -I. -I../../../../Trolltech/Qt-4.4.1/include/QtCore -I../../../../Trolltech/Qt-4.4.1/include/QtCore -I../../../../Trolltech/Qt-4.4.1/include/QtGui -I../../../../Trolltech/Qt-4.4.1/include/QtGui -I../../../../Trolltech/Qt-4.4.1/include/Qt3Support -I../../../../Trolltech/Qt-4.4.1/include/Qt3Support -I../../../../Trolltech/Qt-4.4.1/include -I. -I.
 
LINK          = g++
 
LFLAGS        = -m64 -fPIC -Wl,-rpath,/ufs/merks/Trolltech/Qt-4.4.1/lib -shared
 
LIBS          = $(SUBLIBS)  -L/ufs/merks/Trolltech/Qt-4.4.1/lib -L../../lib -lvleaf -lQt3Support -L/ufs/merks/Trolltech/Qt-4.4.1/lib -lQtSql -pthread -pthread -pthread -pthread -lQtXml -pthread -pthread -pthread -pthread -L/usr/X11R6/lib64 -pthread -pthread -pthread -pthread -pthread -pthread -lQtNetwork -pthread -pthread -pthread -pthread -pthread -pthread -lQtGui -pthread -lpng -lSM -lICE -pthread -pthread -lXi -lXrender -lXrandr -lfreetype -lfontconfig -lXext -lX11 -lQtCore -lz -lm -pthread -lgthread-2.0 -lrt -lglib-2.0 -ldl -lpthread
 
AR            = ar cqs
 
RANLIB        = 
 
QMAKE         = /ufs/merks/Trolltech/Qt-4.4.1/bin/qmake
 
TAR           = tar -cf
 
COMPRESS      = gzip -9f
 
COPY          = cp -f
 
SED           = sed
 
COPY_FILE     = $(COPY)
 
COPY_DIR      = $(COPY) -r
 
INSTALL_FILE  = install -m 644 -p
 
INSTALL_DIR   = $(COPY_DIR)
 
INSTALL_PROGRAM = install -m 755 -p
 
DEL_FILE      = rm -f
 
SYMLINK       = ln -sf
 
DEL_DIR       = rmdir
 
MOVE          = mv -f
 
CHK_DIR_EXISTS= test -d
 
MKDIR         = mkdir -p
 

	
 
plugin_auxingrowth: Makefile.plugin_auxingrowth
 
	make -f Makefile.plugin_auxingrowth
 
####### Output directory
 

	
 
OBJECTS_DIR   = ./
 

	
 
####### Files
 

	
 
Makefile.plugin_auxingrowth: plugin_auxingrowth.pro
 
	$(QMAKE) -makefile -o $@ $< 
 
SOURCES       = auxinsimon.cpp moc_auxinsimon.cpp
 
OBJECTS       = auxinsimon.o \
 
		moc_auxinsimon.o
 
DIST          = ../../../../Trolltech/Qt-4.4.1/mkspecs/common/g++.conf \
 
		../../../../Trolltech/Qt-4.4.1/mkspecs/common/unix.conf \
 
		../../../../Trolltech/Qt-4.4.1/mkspecs/common/linux.conf \
 
		../../../../Trolltech/Qt-4.4.1/mkspecs/qconfig.pri \
 
		../../../../Trolltech/Qt-4.4.1/mkspecs/features/qt_functions.prf \
 
		../../../../Trolltech/Qt-4.4.1/mkspecs/features/qt_config.prf \
 
		../../../../Trolltech/Qt-4.4.1/mkspecs/features/exclusive_builds.prf \
 
		../../../../Trolltech/Qt-4.4.1/mkspecs/features/default_pre.prf \
 
		../../../../Trolltech/Qt-4.4.1/mkspecs/features/release.prf \
 
		../../../../Trolltech/Qt-4.4.1/mkspecs/features/default_post.prf \
 
		../../../../Trolltech/Qt-4.4.1/mkspecs/features/warn_on.prf \
 
		../../../../Trolltech/Qt-4.4.1/mkspecs/features/qt.prf \
 
		../../../../Trolltech/Qt-4.4.1/mkspecs/features/unix/thread.prf \
 
		../../../../Trolltech/Qt-4.4.1/mkspecs/features/moc.prf \
 
		../../../../Trolltech/Qt-4.4.1/mkspecs/features/resources.prf \
 
		../../../../Trolltech/Qt-4.4.1/mkspecs/features/uic.prf \
 
		../../../../Trolltech/Qt-4.4.1/mkspecs/features/yacc.prf \
 
		../../../../Trolltech/Qt-4.4.1/mkspecs/features/lex.prf \
 
		auxinsimon.pro
 
QMAKE_TARGET  = auxinsimon
 
DESTDIR       = ../../bin/models/
 
TARGET        = libauxinsimon.so
 
TARGETD       = libauxinsimon.so
 

	
 
plugin_leaf: Makefile.plugin_leaf
 
	make -f Makefile.plugin_leaf
 
first: all
 
####### Implicit rules
 

	
 
.SUFFIXES: .o .c .cpp .cc .cxx .C
 

	
 
.cpp.o:
 
	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<"
 

	
 
.cc.o:
 
	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<"
 

	
 
.cxx.o:
 
	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<"
 

	
 
Makefile.plugin_leaf: plugin_leaf.pro
 
	$(QMAKE) -makefile -o $@ $< 
 
.C.o:
 
	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<"
 

	
 
.c.o:
 
	$(CC) -c $(CFLAGS) $(INCPATH) -o "$@" "$<"
 

	
 
####### Build rules
 

	
 
all: Makefile  ../../bin/models/$(TARGET)
 

	
 
../../bin/models/$(TARGET):  $(OBJECTS) $(SUBLIBS) $(OBJCOMP)  
 
	@$(CHK_DIR_EXISTS) ../../bin/models/ || $(MKDIR) ../../bin/models/ 
 
	-$(DEL_FILE) $(TARGET)
 
	$(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(LIBS) $(OBJCOMP)
 
	-$(MOVE) $(TARGET) ../../bin/models/
 

	
 

	
 

	
 
plugin_meinhardt: Makefile.plugin_meinhardt
 
	make -f Makefile.plugin_meinhardt
 
Makefile: auxinsimon.pro  ../../../../Trolltech/Qt-4.4.1/mkspecs/linux-g++-64/qmake.conf ../../../../Trolltech/Qt-4.4.1/mkspecs/common/g++.conf \
 
		../../../../Trolltech/Qt-4.4.1/mkspecs/common/unix.conf \
 
		../../../../Trolltech/Qt-4.4.1/mkspecs/common/linux.conf \
 
		../../../../Trolltech/Qt-4.4.1/mkspecs/qconfig.pri \
 
		../../../../Trolltech/Qt-4.4.1/mkspecs/features/qt_functions.prf \
 
		../../../../Trolltech/Qt-4.4.1/mkspecs/features/qt_config.prf \
 
		../../../../Trolltech/Qt-4.4.1/mkspecs/features/exclusive_builds.prf \
 
		../../../../Trolltech/Qt-4.4.1/mkspecs/features/default_pre.prf \
 
		../../../../Trolltech/Qt-4.4.1/mkspecs/features/release.prf \
 
		../../../../Trolltech/Qt-4.4.1/mkspecs/features/default_post.prf \
 
		../../../../Trolltech/Qt-4.4.1/mkspecs/features/warn_on.prf \
 
		../../../../Trolltech/Qt-4.4.1/mkspecs/features/qt.prf \
 
		../../../../Trolltech/Qt-4.4.1/mkspecs/features/unix/thread.prf \
 
		../../../../Trolltech/Qt-4.4.1/mkspecs/features/moc.prf \
 
		../../../../Trolltech/Qt-4.4.1/mkspecs/features/resources.prf \
 
		../../../../Trolltech/Qt-4.4.1/mkspecs/features/uic.prf \
 
		../../../../Trolltech/Qt-4.4.1/mkspecs/features/yacc.prf \
 
		../../../../Trolltech/Qt-4.4.1/mkspecs/features/lex.prf \
 
		/ufs/merks/Trolltech/Qt-4.4.1/lib/libQt3Support.prl \
 
		/ufs/merks/Trolltech/Qt-4.4.1/lib/libQtSql.prl \
 
		/ufs/merks/Trolltech/Qt-4.4.1/lib/libQtCore.prl \
 
		/ufs/merks/Trolltech/Qt-4.4.1/lib/libQtXml.prl \
 
		/ufs/merks/Trolltech/Qt-4.4.1/lib/libQtGui.prl \
 
		/ufs/merks/Trolltech/Qt-4.4.1/lib/libQtNetwork.prl
 
	$(QMAKE) -unix -o Makefile auxinsimon.pro
 
../../../../Trolltech/Qt-4.4.1/mkspecs/common/g++.conf:
 
../../../../Trolltech/Qt-4.4.1/mkspecs/common/unix.conf:
 
../../../../Trolltech/Qt-4.4.1/mkspecs/common/linux.conf:
 
../../../../Trolltech/Qt-4.4.1/mkspecs/qconfig.pri:
 
../../../../Trolltech/Qt-4.4.1/mkspecs/features/qt_functions.prf:
 
../../../../Trolltech/Qt-4.4.1/mkspecs/features/qt_config.prf:
 
../../../../Trolltech/Qt-4.4.1/mkspecs/features/exclusive_builds.prf:
 
../../../../Trolltech/Qt-4.4.1/mkspecs/features/default_pre.prf:
 
../../../../Trolltech/Qt-4.4.1/mkspecs/features/release.prf:
 
../../../../Trolltech/Qt-4.4.1/mkspecs/features/default_post.prf:
 
../../../../Trolltech/Qt-4.4.1/mkspecs/features/warn_on.prf:
 
../../../../Trolltech/Qt-4.4.1/mkspecs/features/qt.prf:
 
../../../../Trolltech/Qt-4.4.1/mkspecs/features/unix/thread.prf:
 
../../../../Trolltech/Qt-4.4.1/mkspecs/features/moc.prf:
 
../../../../Trolltech/Qt-4.4.1/mkspecs/features/resources.prf:
 
../../../../Trolltech/Qt-4.4.1/mkspecs/features/uic.prf:
 
../../../../Trolltech/Qt-4.4.1/mkspecs/features/yacc.prf:
 
../../../../Trolltech/Qt-4.4.1/mkspecs/features/lex.prf:
 
/ufs/merks/Trolltech/Qt-4.4.1/lib/libQt3Support.prl:
 
/ufs/merks/Trolltech/Qt-4.4.1/lib/libQtSql.prl:
 
/ufs/merks/Trolltech/Qt-4.4.1/lib/libQtCore.prl:
 
/ufs/merks/Trolltech/Qt-4.4.1/lib/libQtXml.prl:
 
/ufs/merks/Trolltech/Qt-4.4.1/lib/libQtGui.prl:
 
/ufs/merks/Trolltech/Qt-4.4.1/lib/libQtNetwork.prl:
 
qmake:  FORCE
 
	@$(QMAKE) -unix -o Makefile auxinsimon.pro
 

	
 
Makefile.plugin_meinhardt: plugin_meinhardt.pro
 
	$(QMAKE) -makefile -o $@ $< 
 
dist: 
 
	@$(CHK_DIR_EXISTS) .tmp/auxinsimon1.0.0 || $(MKDIR) .tmp/auxinsimon1.0.0 
 
	$(COPY_FILE) --parents $(SOURCES) $(DIST) .tmp/auxinsimon1.0.0/ && $(COPY_FILE) --parents ../simplugin.h auxinsimon.h .tmp/auxinsimon1.0.0/ && $(COPY_FILE) --parents auxinsimon.cpp .tmp/auxinsimon1.0.0/ && (cd `dirname .tmp/auxinsimon1.0.0` && $(TAR) auxinsimon1.0.0.tar auxinsimon1.0.0 && $(COMPRESS) auxinsimon1.0.0.tar) && $(MOVE) `dirname .tmp/auxinsimon1.0.0`/auxinsimon1.0.0.tar.gz . && $(DEL_FILE) -r .tmp/auxinsimon1.0.0
 

	
 

	
 
plugin_test: Makefile.plugin_test
 
	make -f Makefile.plugin_test
 
clean:compiler_clean 
 
	-$(DEL_FILE) $(OBJECTS)
 
	-$(DEL_FILE) *~ core *.core
 

	
 

	
 
####### Sub-libraries
 

	
 
Makefile.plugin_test: plugin_test.pro
 
	$(QMAKE) -makefile -o $@ $< 
 
distclean: clean
 
	-$(DEL_FILE) $(TARGET) 
 
	-$(DEL_FILE) Makefile
 

	
 

	
 
mocclean: compiler_moc_header_clean compiler_moc_source_clean
 

	
 
mocables: compiler_moc_header_make_all compiler_moc_source_make_all
 

	
 
compiler_moc_header_make_all: moc_auxinsimon.cpp
 
compiler_moc_header_clean:
 
	-$(DEL_FILE) moc_auxinsimon.cpp
 
moc_auxinsimon.cpp: ../simplugin.h \
 
		../cellbase.h \
 
		../vector.h \
 
		../sqr.h \
 
		../parameter.h \
 
		../wall.h \
 
		../wallbase.h \
 
		../warning.h \
 
		auxinsimon.h
 
	/ufs/merks/Trolltech/Qt-4.4.1/bin/moc $(DEFINES) $(INCPATH) auxinsimon.h -o moc_auxinsimon.cpp
 

	
 
clean:
 
	make -f Makefile.plugin_auxingrowth clean
 
	make -f Makefile.plugin_leaf clean
 
	make -f Makefile.plugin_meinhardt clean
 
	make -f Makefile.plugin_test clean
 
compiler_rcc_make_all:
 
compiler_rcc_clean:
 
compiler_image_collection_make_all: qmake_image_collection.cpp
 
compiler_image_collection_clean:
 
	-$(DEL_FILE) qmake_image_collection.cpp
 
compiler_moc_source_make_all:
 
compiler_moc_source_clean:
 
compiler_uic_make_all:
 
compiler_uic_clean:
 
compiler_yacc_decl_make_all:
 
compiler_yacc_decl_clean:
 
compiler_yacc_impl_make_all:
 
compiler_yacc_impl_clean:
 
compiler_lex_make_all:
 
compiler_lex_clean:
 
compiler_clean: compiler_moc_header_clean 
 

	
 
####### Compile
 

	
 
#finis
 
auxinsimon.o: auxinsimon.cpp ../simplugin.h \
 
		../cellbase.h \
 
		../vector.h \
 
		../sqr.h \
 
		../parameter.h \
 
		../wall.h \
 
		../wallbase.h \
 
		../warning.h \
 
		auxinsimon.h
 
	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o auxinsimon.o auxinsimon.cpp
 

	
 
moc_auxinsimon.o: moc_auxinsimon.cpp 
 
	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_auxinsimon.o moc_auxinsimon.cpp
 

	
 
####### Install
 

	
 
install:   FORCE
 

	
 
uninstall:   FORCE
 

	
 
FORCE:
 

	
src/canvas.cpp
Show inline comments
 
@@ -181,768 +181,770 @@ void FigureEditor::mousePressEvent(QMous
 
    - intersection_line->line().p1();
 
    QPointF q_v2 = angle_line->line().p2();
 
    - angle_line->line().p1();
 
    
 
    Vector v1(q_v1.x(),q_v1.y());
 
    Vector v2(q_v2.x(),q_v2.y());
 
    
 
    cerr << "v1 = " << v1 << endl;
 
    cerr << "v2 = " << v2 << endl;
 
    
 
    
 
    rot_angle = v1.SignedAngle(v2);
 
    cerr << "Angle is " << rot_angle << endl;
 
    
 
    const QPointF &q_c(angle_line->line().p1());
 
    Vector center = Vector(q_c.x(), q_c.y()) / Cell::Factor() - Cell::Offset();
 
    
 
    cerr << "Center is " << center << endl;
 
    
 
    mesh.Rotate(rot_angle, center);
 
    delete angle_line;
 
    angle_line=0;
 
    delete intersection_line;
 
    intersection_line=0;
 
    
 
    viewport()->setMouseTracking( FALSE );
 
    dynamic_cast<Main *>(parent())->Plot();
 
    
 
    
 
    return;
 
    
 
    }*/
 
  
 
   
 
    if (e->button()==Qt::RightButton || l.size()==0) {
 
    
 
      //cerr << "Drawing an intersection line from " << p.x() << ", " << p.y() << endl;
 
      intersection_line = new QGraphicsLineItem( 0, scene() );
 
      intersection_line->setPen( QPen( QColor("red"), 3, Qt::DashLine ) );
 
      intersection_line->setLine( QLineF(p,p) );
 
      intersection_line->setZValue( 100 );
 
      intersection_line->show();
 
    }
 
  
 
    for (QList<QGraphicsItem *>::Iterator it=l.begin(); it!=l.end(); ++it) {
 
      /*if ( (*it)->rtti() == imageRTTI ) {
 
	ImageItem *item= (ImageItem*)(*it);
 
	if ( !item->hit( p ) )
 
	continue;
 
	}*/
 
      cerr << typeid(**it).name() << endl;
 
    
 
      if ( !strcmp(typeid(**it).name(),"8NodeItem")) {
 
	//moving = dynamic_cast<NodeItem*>(*it);
 
	//moving = *it;
 
	//moving_start = p;
 
      
 
	stringstream data_strstream;
 
	data_strstream << (dynamic_cast<NodeItem*>(*it))->getNode();
 
	dynamic_cast<Main *>(parent())->UserMessage(QString(data_strstream.str().c_str()));
 
      
 
	(dynamic_cast<NodeItem*>(*it))->OnClick(e->button());
 
      }
 
      else 
 
	if ( !strcmp(typeid(**it).name(),"8CellItem") ) {
 
      
 
	  Cell &c=((dynamic_cast<CellItem *>(*it))->getCell());      
 
	  //static int old_stride=100;
 
	  //if (!c.Source()) {
 
	  /* if (!c.Source()) {
 
	     c.SetChemical(0,par.cellsource);
 
	     //flag=true;
 
	     //c.SetSource(0,par.cellsource);
 
	     //c.Fix();
 
	     //cerr << "Setting source\n";
 
			
 
	     } else { 
 
	     //c.UnsetSource();
 
	     cerr << "Unsetting source\n";
 
	     } */
 
	  // OnClick to be defined in end-user code
 
	  c.OnClick(e);
 
	} else {
 
	  if ( !strcmp(typeid(**it).name(),"8WallItem") ) {
 
	    (dynamic_cast<WallItem *>(*it))->OnClick(e);
 
	  } 
 
	}
 
    }
 

	
 
  FullRedraw();
 
  moving = 0;
 
}
 
  
 
//void FigureEditor::contentsMouseMoveEvent(QMouseEvent* e)
 
void FigureEditor::mouseMoveEvent(QMouseEvent* e)
 
{
 

	
 
  // User choose "rotation mode" and we can rotate the object around its center of mass
 
  if (dynamic_cast<Main *>(parent())->RotationModeP()) {
 

	
 
    QPointF p = mapToScene(e->pos());
 
    p.setX(p.x() / Cell::Magnification());
 
    p.setY(p.y() / Cell::Magnification());
 

	
 

	
 
    // get object's center of mass
 
    QPointF rotation_midpoint = mesh.Centroid()*Cell::Factor() - Cell::Offset();
 
    
 
        
 
    // calculate rotation angle
 
    double dy = (rotation_midpoint.y() - p.y());
 
    double dx = (rotation_midpoint.x() - p.x());
 
    double new_rot_angle = atan2(dx, dy);
 
    double d_alpha = new_rot_angle - rot_angle;
 
    rot_angle = new_rot_angle;
 
    
 
    mesh.Rotate(d_alpha, ( Vector(rotation_midpoint) + Cell::Offset() ) / Cell::Factor() );
 
    
 
    //viewport()->setMouseTracking( FALSE );
 
    dynamic_cast<Main *>(parent())->Plot(0);
 
	  FullRedraw();
 
    return;
 
  }
 
  if ( moving ) {
 
    //QPoint p = matrix().inverted().map(e->pos());
 
    QPointF p = mapToScene(e->pos());
 
    
 
    moving->userMove(p.x() - moving_start.x(),
 
		     p.y() - moving_start.y());
 
    moving_start = p;
 
    scene()->update();
 
    
 
  }
 
  
 
  //cerr << "event";
 
  
 
  // keep track of intersection line to interactively cut a growing leaf
 
  /* if (angle_line) {
 

	
 
    QPointF sp = angle_line -> line().p1(); // startpoint
 
    //QPointF ep = matrix().inverted().map(e->pos()); // endpoint
 
    QPointF ep = mapToScene(e->pos()); // endpoint
 
    angle_line -> setLine( QLineF(sp, ep) ); 
 
    scene()->update();
 
  
 
    } else { */
 
    
 
  if ( intersection_line ) {
 
    
 
    QPointF sp = intersection_line -> line().p1(); // startpoint
 
    //QPointF ep = matrix().inverted().map(e->pos()); // endpoint
 
    QPointF ep = mapToScene(e->pos()); // endpoint
 
    intersection_line -> setLine( QLineF(sp, ep) ); 
 
    scene()->update();
 
    // Need this for Mac
 
    FullRedraw();
 
    }
 
  /* } */
 
  
 
}
 

	
 
//void FigureEditor::contentsMouseReleaseEvent(QMouseEvent* e)
 
void FigureEditor::mouseReleaseEvent(QMouseEvent* e)
 
{
 
  
 
  emit MouseReleased();
 
  // intersection line for leaf was finished now.
 
  
 
  if (e->button()==Qt::LeftButton) { 
 
    if (intersection_line ) {
 
    
 
      cerr << "Trying to cut leaf\n";
 
      QPointF sp = intersection_line -> line().p1(); // startpoint
 
      //QPointF ep = matrix().inverted().map(e->pos()); // endpoint
 
      QPointF ep = mapToScene(e->pos());
 

	
 
      intersection_line -> setLine( QLineF(sp, ep) ); 
 
      intersection_line -> show();
 

	
 
      vector <CellItem *> intersected_cells = getIntersectedCells();
 
    
 
      // no cells selected, do nothing
 
      if (intersected_cells.size()==0) {
 
	cerr << "No cells detected :-( \n";
 
	return;
 
      }
 
      
 
    
 
      Vector startpoint = Vector(sp.x(), sp.y()) / Cell::Factor() - Cell::Offset();
 
      Vector endpoint = Vector(ep.x(), ep.y()) / Cell::Factor() - Cell::Offset();
 
    
 
      // Mesh &m(intersected_cells.front()->getCell().getMesh());
 
      NodeSet *node_set = new NodeSet;
 
      
 
      for (vector<CellItem *>::iterator it = intersected_cells.begin();
 
	   it != intersected_cells.end();
 
	   it++) {
 
      
 
	//(*it)->Mark();
 
	(*it)->setBrush(QBrush("purple"));
 
       
 
	Cell &c=(*it)->getCell();
 
      
 
	// sometimes the cell hasn't properly divided yet before the
 
	// next division is called?  so check for it?  let's find a way
 
	// to do this later. Note that this functionality currently
 
	// might result in a segmentation fault for users who are
 
	// quickly dragging and releasing division lines...
 
	scene()->update();
 
	
 
	cerr << "Dividing Cell " << c.Index() << endl;
 
	c.DivideOverGivenLine( startpoint, endpoint, true, node_set);
 
      }
 
      
 
      node_set->CleanUp();
 
      mesh.AddNodeSet(node_set);
 
      
 
      cerr << "Done DivideOverGivenLine\n";
 
      mesh.TestIllegalWalls();
 
      // Do the actual cutting and removing
 
      if (intersected_cells.size()) {
 
	//      Mesh &m(intersected_cells.front()->getCell().getMesh());
 
	mesh.CutAwayBelowLine( startpoint, endpoint ); 
 
	
 
	// Correct flags of nodeset
 
	for (
 
	     NodeSet::iterator i = node_set->begin(); 
 
	     i != node_set->end();
 
	     i++) {
 
	  (*i)->SetSAM();
 
	  (*i)->SetBoundary();
 
	}
 

	
 
	// Make cells attached to nodeset part of the boundary
 
	// This is a temporary solution for the following:
 
	//   If a cell attached to a NodeSet divides (with a division plane intersecting the node set), 
 
	//   we must insert a new node into the node set.
 
	// For now, we add a layer of "virtual cells" inbetween. 
 
	list<Cell *> cells_attached_to_nodeset = node_set->getCells();
 
	for ( list<Cell *>::iterator c = cells_attached_to_nodeset.begin();
 
	      c != cells_attached_to_nodeset.end(); 
 
	      c++) {
 
	  (*c)->SetBoundary(Cell::SAM);
 
	}
 

	
 

	
 

	
 
	cerr << "Done CutAwayBelowLine\n";
 
	mesh.TestIllegalWalls();
 
	mesh.RepairBoundaryPolygon();
 
	cerr << "Done RepairBoundaryPolygon\n";
 
	mesh.TestIllegalWalls();
 
	mesh.CleanUpWalls();
 
	cerr << "Done CleanUpWalls\n";
 
	mesh.TestIllegalWalls();
 
      }
 
      
 
      dynamic_cast<Main *>(parent())->Plot();
 
      
 
      cerr << "NodeSet of cutting line: " << *node_set << endl;
 

	
 
    }
 
  } else 
 
    if (e->button()==Qt::RightButton) {
 
      
 
      if (intersection_line /* && !angle_line*/) {
 
	
 
	//QPointF p = matrix().inverted().map(e->pos());
 
	QPointF p = mapToScene(e->pos());
 
	QPointF sp = intersection_line->line().p1();
 
	
 
	viewport()->setMouseTracking( TRUE );
 
	/* angle_line = new QGraphicsLineItem( 0, scene() );
 
	angle_line->setPen( QPen( QColor("Blue"), 3, Qt::DashLine ) );
 
	angle_line->setLine( QLineF(sp, p) );
 
	angle_line->setZValue( 100 );
 
	angle_line->show();
 
	*/
 
      } 
 
            
 
    }
 
}
 

	
 

	
 
// returns a vector of pointer to cells colliding with intersection line
 
vector <CellItem *> FigureEditor::getIntersectedCells(void) { 
 
  
 
  vector <CellItem *> colliding_cells;
 
  
 
  QList<QGraphicsItem *> l = intersection_line->collidingItems( );
 
  
 
  cerr << "l.size() = " << l.size() << endl;
 
  for (QList<QGraphicsItem *>::Iterator it=l.begin(); it!=l.end(); ++it) {
 
    
 
    cerr << typeid(**it).name() << endl;
 
    
 
    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)
 
	   
 
	  //canvas(c)
 
{
 
  editor = new FigureEditor(canvas,mesh, this);
 
  cerr << "Interactive = " << editor->isEnabled();
 
  working_dir = 0;
 
  QObject::connect( editor, SIGNAL(MousePressed()), this, SLOT(PauseIfRunning()));
 
  QObject::connect( editor, SIGNAL(MouseReleased()), this, SLOT(ContIfRunning()));
 
  QMenuBar* menu = menuBar();
 
  
 
  Q3PopupMenu* file = new Q3PopupMenu( menu );
 
 // file->insertItem("&Fill canvas", this, SLOT(init()), Qt::CTRL+Qt::Key_F);
 
	file->insertItem("&Read leaf", this, SLOT(readStateXML()));
 
	file->insertItem("&Save leaf", this, SLOT(saveStateXML()));
 
	file->insertItem("Snapshot", this, SLOT(snapshot()), Qt::CTRL+Qt::SHIFT+Qt::Key_S);
 
 // file->insertItem("&New view", this, SLOT(newView()), Qt::CTRL+Qt::Key_N);
 
   file->insertSeparator();
 
	file->insertItem("Read next leaf", this, SLOT(readNextStateXML()), Qt::Key_PageDown);
 
	file->insertItem("Read previous leaf", this, SLOT(readPrevStateXML()), Qt::Key_PageUp);
 
	file->insertItem("Read last leaf", this, SLOT(readLastStateXML()), Qt::Key_End);
 
	file->insertItem("Read first leaf", this, SLOT(readFirstStateXML()), Qt::Key_Home);
 
	//file->insertItem("Read &parameters", this, SLOT(readPars()));
 
  //file->insertItem("&Write parameters", this, SLOT(savePars()));
 
	
 
	file->insertSeparator();
 
	file->insertItem("&Print...", this, SLOT(print()), Qt::CTRL+Qt::Key_P);
 
	file->insertSeparator();
 
	file->insertItem("E&xit", qApp, SLOT(quit()), Qt::CTRL+Qt::Key_Q);
 
	menu->insertItem("&File", file);
 
	
 
	Q3PopupMenu* edit = new Q3PopupMenu( menu );
 
  edit->insertItem("Reset Chemicals and Transporters", this, SLOT( CleanMesh()), Qt::CTRL+Qt::Key_R );
 
	edit->insertItem("Reset Chemicals", this, SLOT( CleanMeshChemicals()) );
 
	edit->insertItem("Reset Transporters", this, SLOT( CleanMeshTransporters()) );
 
  edit->insertItem("Randomize PIN1 Transporters", this, SLOT( RandomizeMesh()) );
 
  edit->insertItem("Cut away SAM", this, SLOT( CutSAM() ));
 
  menu->insertItem("&Edit", edit);
 

	
 
  run = new Q3PopupMenu( menu );
 
  //  edit->insertItem("Add &Polygon", this, SLOT(addPolygon()), ALT+Key_P);
 
  //edit->insertItem("Add &Line", this, SLOT(addLine()), ALT+Key_L);
 
  running = false;
 
	paused_id = run->insertItem("&Simulation paused", this, SLOT(togglePaused()), Qt::Key_S);
 
  run->setItemChecked(paused_id, FALSE);
 

	
 
  //run->insertItem("&Divide Cell", this, SLOT(Divide()), Qt::CTRL+Qt::Key_D);
 
 // run->insertItem("&Restart Simulation", this, SLOT(RestartSim())); 
 
  menu->insertItem("&Run", run);
 
  
 
  view = new Q3PopupMenu( menu );
 
  //view->insertItem("&Enlarge", this, SLOT(enlarge()), SHIFT+CTRL+Key_Plus);
 
  //view->insertItem("Shr&ink", this, SLOT(shrink()), SHIFT+CTRL+Key_Minus);
 
	view->insertItem("&Zoom in", this, SLOT(zoomIn()), Qt::CTRL+Qt::Key_Equal);
 
  view->insertItem("Zoom &out", this, SLOT(zoomOut()), Qt::CTRL+Qt::Key_Minus);
 
	view->insertSeparator();
 
	com_id = view->insertItem("Show cell &centers", this, SLOT(toggleShowCellCenters()));
 
  view->setItemChecked(com_id, FALSE);
 
  //view->insertItem("Cell monitor", this, SLOT(cellmonitor()));
 
  mesh_id = view->insertItem("Show &nodes", this, SLOT(toggleShowNodes()), Qt::CTRL+Qt::SHIFT+Qt::Key_N);
 
  view->setItemChecked(mesh_id, TRUE);
 
  node_number_id = view->insertItem("Show node numbers", this, SLOT(toggleNodeNumbers()), Qt::CTRL+Qt::SHIFT+Qt::Key_M);
 
  view->setItemChecked(node_number_id, TRUE);
 
  cell_number_id = view->insertItem("Show cell numbers", this, SLOT(toggleCellNumbers()));
 
  view->setItemChecked(cell_number_id, TRUE);
 
  hide_cells_id = view->insertItem("Hide cells", this, SLOT(toggleHideCells()));
 
  view->setItemChecked(hide_cells_id, FALSE);
 
  border_id = view->insertItem("Show &border cells", this, SLOT(toggleShowBorderCells()));
 
  view->setItemChecked(border_id, FALSE);
 
  cell_axes_id = view->insertItem("Show cell &axes", this, SLOT(toggleCellAxes()));
 
  cell_strain_id = view->insertItem("Show cell &strain", this, SLOT(toggleCellStrain()));
 
  view->setItemChecked(cell_axes_id, FALSE);
 
  fluxes_id = view->insertItem("Show &fluxes", this, SLOT(toggleShowFluxes()));
 
  view->setItemChecked(fluxes_id, FALSE);
 
  cell_walls_id = view->insertItem("Show transporters", this, SLOT(toggleShowWalls()));
 
	view->setItemChecked(cell_walls_id, FALSE);
 
	apoplasts_id = view->insertItem("Show apoplasts", this, SLOT(toggleShowApoplasts()));
 
  view->setItemChecked(apoplasts_id, FALSE);
 
 	view->insertSeparator();
 
	  only_boundary_id = view->insertItem("Show only leaf &boundary", this, SLOT(toggleLeafBoundary()));
 
  //only_boundary_id = view->insertItem("Show only leaf &boundary", 0,0);
 
	view->insertSeparator();
 
	movie_frames_id = view->insertItem("Start saving movie &frames", this, SLOT(toggleMovieFrames()));
 
  view->setItemChecked(movie_frames_id, par.movie);
 
	
 
	view->setItemChecked(only_boundary_id, FALSE);
 
  menu->insertItem("&View", view);
 
  
 
  
 
  options = new Q3PopupMenu( menu );
 
  /* dbf_id = options->insertItem("Double buffer", this, SLOT(toggleDoubleBuffer()));
 
     options->setItemChecked(dbf_id, TRUE);*/
 
  dyn_cells_id = options->insertItem("Cell growth", this, SLOT(toggleDynCells()));
 
  options->setItemChecked(dyn_cells_id, true);
 

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

	
 
  menu->insertItem("&Options",options);
 
	
 
	// Menu of models
 
	modelmenu = new QMenu( menu );
 
	menu->insertItem("&Models", modelmenu);
 
	
 
	
 
  menu->insertSeparator();
 
  
 
  helpmenu = new Q3PopupMenu( menu );
 
  tooltips_id = helpmenu->insertItem("Show Cell&Info", this, SLOT(Refresh()));
 
  helpmenu->setItemChecked(tooltips_id, true);
 
  helpmenu->insertSeparator();
 

	
 
  helpmenu->insertItem("&About", this, SLOT(help()) ); //, Key_F1);
 
  //help->insertItem( "What's &This", this , SLOT(whatsThis()), SHIFT+Key_F1);
 
  menu->insertItem("&Help",helpmenu);
 
  //QSlider *flux_arrow_slider = new QSlider( 0, 10000, 1, 100, Qt::Horizontal, this, "flux arrow size");
 
  //QSpinBox *stride  = new QSpinBox( 1, 1000, 1, this, "stride");
 
  
 
	    
 
  //QGridLayout *controlgrid = new QGridLayout( this, 1, 2, 10);
 
  // 2x1, 10 pixel border
 
  
 
  //controlgrid->addWidget( stride, 0, 0);
 
  //controlgrid->addWidget( flux_arrow_slider, 0, 1);
 
  //controlgrid->setColStretch( 1, 10 );
 
  
 
  
 
  //flux_arrow_size = 1.;
 
  //flux_arrow_slider -> setMinimumSize( 200,50);
 
  //connect( flux_arrow_slider, SIGNAL( valueChanged( int ) ), this, SLOT( setFluxArrowSize(int) ) );
 
  
 
  statusBar();
 
  
 
  setCentralWidget(editor);
 

	
 
  printer = 0;
 

	
 
  init();
 
    
 
  // Start timer which repetitively invokes
 
  // a simulation time step
 
  timer = new QTimer( this );
 
  connect( timer, SIGNAL(timeout()), SLOT(TimeStepWrap()) );
 
  
 
  stopSimulation();
 
  statusBar()->addWidget(new QLabel("Ready."));
 
  setCaption(caption);
 
  gifanim = 0;
 
	
 
	// A little bit of PSB/CWI decoration ;-)
 
	/*dockwindow = new Q3DockWindow();
 
	addDockWindow(dockwindow);
 
	QLabel *viblab = new QLabel; viblab->setPixmap(QPixmap(cwi_xpm));
 
	QString virtleafstring("<h1>The Virtual Leaf</h1>\n<center><b>Model:</b> <i>%1</i></center>");
 
	QLabel *virtleaf = new QLabel(virtleafstring.arg(mesh.ModelID()));
 
	QLabel *psblab = new QLabel; psblab->setPixmap(QPixmap(PSB_xpm));
 
	dockwindow->setHorizontalStretchable(true);
 
	dockwindow->boxLayout()->addWidget(viblab);//,Qt::AlignLeft);
 
	dockwindow->boxLayout()->addStretch();
 
	dockwindow->boxLayout()->addWidget(virtleaf);//, Qt::AlignHCenter);
 
	dockwindow->boxLayout()->addStretch();
 
	dockwindow->boxLayout()->addWidget(psblab);//, Qt::AlignRight);*/
 
	//QString virtleafstring("<h1>The Virtual Leaf</h1>\n<center><b>Model:</b> <i>%1</i></center>");
 
	infobar = new InfoBar();
 
	addDockWindow(infobar);
 

	
 
}
 

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

	
 

	
 
void Main::UserMessage(QString message, int timeout) {
 

	
 
  statusBar()->showMessage(message, timeout);
 

	
 
}
 

	
 

	
 
void Main::init()
 
{
 
  clear();
 
  
 
  static int r=24;
 
  srand(++r);
 
  
 
  mainCount++;
 
  
 
  
 
}
 

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

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

	
 

	
 
void Main::EditParameters() {
 
  
 
  ParameterDialog *pardial = new ParameterDialog(this, "stridediag");
 

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

	
 
}
 

	
 
void Main::savePars() {
 
  
 
  // bool timer_active;
 
  /* if (timer_active=timer->isActive())
 
     imer->stop();*/
 
  stopSimulation();
 
  
 
  Q3FileDialog *fd = new Q3FileDialog( this, "file dialog", TRUE );
 
  fd->setMode( Q3FileDialog::AnyFile );
 
  fd->setFilter( "Parameter files (*.par)");
 

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

	
 
  startSimulation();
 

	
 
}
 

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

	
 
  QString fileName;
 
  if ( fd->exec() == QDialog::Accepted ) {
 
    fileName = fd->selectedFile();
 
    par.Read((const char *)fileName);
 
  }
 
  
 
  emit ParsChanged();
 
  /* if (timer_active)
 
     timer->start( 0 );*/
 
  
 
}
 

	
 

	
 
void Main::saveStateXML() {
 
  
 
   
 
  //   bool timer_active;
 
  //   if (timer_active=timer->isActive())
 
  //     timer->stop();
 
  stopSimulation();
 
  Q3FileDialog *fd = new Q3FileDialog( this, "file dialog", TRUE );
 
  fd->setMode( Q3FileDialog::AnyFile );
 
  fd->setFilter( "XML (*.xml)");
 
  QString fileName;
 
  
 
  if ( fd->exec() == QDialog::Accepted ) {
 
    fileName = fd->selectedFile();
 
    if ( QFile::exists( fileName ) &&
 
	 QMessageBox::question(
 
			       this,
 
			       tr("Overwrite File? -- Leaf Growth"),
 
			       tr("A file called %1 already exists."
 
				  "Do you want to overwrite it?")
 
			       .arg( fileName ),
 
			       tr("&Yes"), tr("&No"),
 
			       QString::null, 1, 1 ) ) {
 
      return saveStateXML();
 
      
 
    } else {
 
      
 
      mesh.XMLSave((const char *)fileName, XMLSettingsTree());
 
    
 
    }
 
  }
 

	
 
}
 

	
 

	
 

	
 
void Main::snapshot() {
 
  
 
   
 
  //   bool timer_active;
 
  //   if (timer_active=timer->isActive())
 
  //     timer->stop();
 
  stopSimulation();
 
  Q3FileDialog *fd = new Q3FileDialog( this, "Save snapshot", TRUE );
 
  fd->setMode( Q3FileDialog::AnyFile );
 
  
 
  QString fileName;
 
  
 
  if ( fd->exec() == QDialog::Accepted ) {
 
    fileName = fd->selectedFile();
 
    if ( QFile::exists( fileName ) &&
 
	 QMessageBox::question(
 
			       this,
 
			       tr("Overwrite File? -- Leaf Growth"),
 
			       tr("A file called %1 already exists."
 
				  "Do you want to overwrite it?")
 
			       .arg( fileName ),
 
			       tr("&Yes"), tr("&No"),
 
			       QString::null, 1, 1 ) ) {
 
      return snapshot();
 
      
 
    } else {
 
      
 
      // extract extension from filename
 
		QString extension = getExtension(fileName);
 
		
 
		// Save bitmaps at 1024x768
 
		Save((const char *)fileName, extension, 1024, 768);
 
    }
 
  }
 

	
 
}
 

	
 
 
 

	
 
void Main::readPrevStateXML() {
 
  
 
  // if we have already read a file, read the next file
 
  if (!currentFile.isEmpty() && working_dir) {
 
    QString next_file;
 
    
 
    QStringList xml_files = working_dir->entryList("*.xml");
 
    QString currentFile_nopath = currentFile.section( '/', -1 );
 
    QString currentFile_path = currentFile.section( '/', 0, -2 );
 
    
 
    QList<QString>::iterator f = xml_files.find( currentFile_nopath );
 
   
 
    if (f == xml_files.end()) {
 
      return;
 
    }
 
    
 
    if (f==xml_files.begin()) {
 
      QMessageBox mb( "Read previous leaf",
 
		      "No more files",
 
		      QMessageBox::Information,
 
		      QMessageBox::Ok | QMessageBox::Default,
 
		      QMessageBox::NoButton,
 
		      QMessageBox::NoButton);
 
      mb.exec();
 
      return;
 
    }
 
    next_file = *(--f);
 
    next_file = currentFile_path+"/"+next_file;
 
    
 
    readStateXML((const char *)next_file);
 
    
 
  }
 
  
 
  
 
}
 

	
 
int Main::readStateXML(const char *filename, bool geometry, bool pars, bool simtime) {
 
 
 
  try {
 
    xmlNode *settings;
 
    mesh.XMLRead((const char *)filename, &settings, geometry, pars, simtime);
 
	cerr << "Reading done.\n";
 
    XMLReadSettings(settings);
 
    xmlFree(settings);
 
    Cell::SetMagnification(1);
 
    Cell::setOffset(0,0);
 
    
 
    FitLeafToCanvas();
 
    
 
    currentFile =  QString(filename);
 
	
 
    Plot();
 
    QString status_message = QString("Succesfully read leaf from file %1. Time is %2 h.\n").arg(currentFile).arg(mesh.getTimeHours().c_str());
 
    cerr << status_message.toStdString() << endl;
 
	setCaption(caption_with_file.arg(filename));
 
    statusBar()->message(status_message);
 
    emit ParsChanged();
 
	cerr << "Done. Returning 0.\n";
 
    return 0;
 
  } catch (const char *error_message) {
 
    QMessageBox mb( "Read leaf from XML file",
 
		    QString(error_message),
 
		    QMessageBox::Critical,
 
		    QMessageBox::Ok | QMessageBox::Default,
 
		    Qt::NoButton,
 
		    Qt::NoButton);
 
    mb.exec();
 
    return 1;
 
  }
 
  
 
}
 

	
 

	
 
void Main::readNextStateXML() {
 
  
 
  // if we have already read a file, read the next file
 
  if (!currentFile.isEmpty() && working_dir) {
 
    QString next_file;
 
@@ -1056,454 +1058,496 @@ void Main::readStateXML() {
 
// 		      QMessageBox::NoButton,
 
// 		      QMessageBox::NoButton);
 
//       mb.exec();
 
//       return readStateXML(); // user can try again
 
//     }
 
    
 
//     Vector bbll,bbur;
 
//     mesh.BoundingBox(bbll,bbur);
 
    
 
//     //FitLeafToCanvas();
 
//     Plot();
 
  }
 
}
 

	
 

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	
 

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

	
 
  void Main::stopSimulation(void) {
 
    //run->setItemChecked(paused_id, true);
 
    timer->stop();
 
    cerr << "Stopping simulation\n";
 
    statusBar()->message("Simulation paused");
 
    running = false;
 
  }
 

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

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

	
 

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

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

	
 
/* void Main::scrollBy(int dx, int dy) {
 
    editor->scrollBy(dx,dy);
 
    }*/
 

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

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

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

	
 

	
 
  void Main::print()
 
  {
 
    if ( !printer ) printer = new QPrinter;
 
    
 
    if ( printer->setup(this) ) {
 
    
 
      //    extern Mesh mesh;
 
      Vector bbll,bbur;
 
      mesh.BoundingBox(bbll,bbur);
 
      cerr << "bbll = " << bbll << endl;
 
      cerr << "bbur = " << bbur << endl;
 
      double cw = (bbur.x - bbll.x);
 
      double ch = (bbur.y - bbll.y);
 
      QPainter pp(printer);
 
      QRect vp=pp.viewport();
 
      cerr << "Paper width = " << vp.width() << " x " << vp.height() << endl;
 
    
 

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

	
 

	
 
  void Main::TimeStepWrap(void) {
 
  
 
    static int t=0;
 
    TimeStep();
 
    t++;
 
    // check number of timesteps
 
    if (t==par.nit) {
 
      emit SimulationDone();
 
    }
 
  }
 

	
 

	
 
  void Main::RestartSim(void) {
 

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

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

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

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

	
 
       }*/
 

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

	
 
       }*/
 

	
 

	
 
void Main::FitCanvasToWindow(void) {
 
  
 
  double scale_factor_x = (double)editor->width()/(double)canvas.width();
 
  double scale_factor_y = (double)editor->height()/(double)canvas.height();
 
  double scale_factor = scale_factor_x > scale_factor_y ? scale_factor_x : scale_factor_y;
 
  QMatrix m = editor->matrix();
 
  
 
  cerr << "editor->width() = " << editor->width() << endl;
 
  cerr << "editor->height() = " << editor->height() << endl;
 
  
 
  cerr << "scale_factor = " << scale_factor << endl;
 
  cerr << "scale_factor_x = " << scale_factor_x << endl;
 
  cerr << "scale_factor_y = " << scale_factor_y << endl;
 
  m.scale( scale_factor, scale_factor );
 
  editor->setMatrix( m );
 
  editor->show();
 
}
 

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

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

	
 
void Main::FitLeafToCanvas(void) {
 

	
 
  Vector ll,ur;
 
  mesh.BoundingBox(ll, ur);
 
  
 
  ll*=Cell::Magnification(); ur*=Cell::Magnification();
 
  
 
  // give the leaf some space
 
  Vector border = ((ur-ll)/5.);
 
  
 
  QRectF bb( ll.x - border.x, ll.y - border.y, ur.x-ll.x + 2*border.x, ur.y-ll.y + 2*border.y );
 
  
 
  
 
  // cerr << ur << ", " << ll << endl;
 
  editor->fitInView(bb, Qt::KeepAspectRatio);
 
}
 

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

	
 
	for (int i=0;i<Cell::NChem();i++) {
 
		clean_chem[i]=par.initval[i];
 
		clean_transporters[i]=0.;		
 
	}
 
	
 
	mesh.CleanChemicals(clean_chem);
 
	mesh.CleanTransporters(clean_transporters);
 
	
 
	mesh.setTime(0);
 
  Plot();
 
  
 
  editor->FullRedraw();
 
 
 
	Plot();
 
	
 
	editor->FullRedraw();
 
	
 
  //  repaint();
 
}
 

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

	
 
	for (int i=0;i<Cell::NChem();i++) {
 
		clean_chem[i]=par.initval[i];
 
	}
 
	
 
	mesh.CleanChemicals(clean_chem);
 
	mesh.setTime(0);
 
	Plot();
 
	
 
	editor->FullRedraw();
 
	
 
	//  repaint();
 
}
 

	
 
void Main::CleanMeshTransporters(void) {
 
	vector<double> clean_transporters(Cell::NChem());
 
	for (int i=0;i<Cell::NChem();i++) {
 
		clean_transporters[i]=0.;
 
	}
 
	
 
	mesh.CleanTransporters(clean_transporters);
 
	
 
	mesh.setTime(0);
 
	Plot();
 
	
 
	editor->FullRedraw();
 
	
 
	//  repaint();
 
}
 

	
 
void Main::RandomizeMesh(void) {
 
  
 
  vector<double> max_chem(Cell::NChem());
 
  vector<double> max_transporters(Cell::NChem());
 
  
 
  for (int i=0;i<Cell::NChem();i++) {
 
    max_transporters[i]=0.;
 
    max_chem[i]=par.initval[i];
 
  }
 

	
 
  // Amount of PIN1 at walls
 
  max_transporters[1] = 0.01;
 
  
 
  mesh.RandomizeChemicals(max_chem, max_transporters);
 
  
 
  Plot();
 
}
 

	
 
void Main::XMLReadSettings(xmlNode *settings) {
 
  
 
  MainBase::XMLReadSettings(settings);
 

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

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

	
 
  return MainBase::XMLSettingsTree();
 
}
 

	
 
/* finis */
 

	
src/canvas.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 _CANVAS_H_
 
#define _CANVAS_H_
 

	
 
#include <q3popupmenu.h>
 
#include <q3mainwindow.h>
 
#include <q3intdict.h>
 
#include <QGraphicsScene>
 
#include <QGraphicsView>
 
#include <QList>
 

	
 
#include <string>
 
#include <sstream>
 

	
 
//Added by qt3to4:
 
#include <QMouseEvent>
 
#include <vector>
 
#include "simitembase.h"
 
#include "mainbase.h"
 
#include "cellitem.h"
 
#include "infobar.h"
 

	
 
#include "nodeitem.h"
 
#include "cell.h"
 

	
 
#ifdef HAVE_QWT
 
#include "data_plot.h"
 
#endif
 

	
 
#include <libxml/xpath.h>
 
#include <libxml/xmlreader.h>
 

	
 
#if defined(Q_OS_MAC)
 
  #define PREFIX "cmd"
 
#else
 
  #define PREFIX "crtl"
 
#endif
 

	
 

	
 
class QFile;
 
class QDir;
 
class ModelCatalogue;
 
class InfoBar;
 

	
 
class FigureEditor : public QGraphicsView {
 
  Q_OBJECT
 

	
 
    friend class Main;
 
    public:
 
  FigureEditor(QGraphicsScene&, Mesh&, QWidget* parent=0, const char* name=0, Qt::WFlags f=0);
 
  void clear();
 
  void Save(const char *fname, const char *format, int sizex=640, int sizey=480);
 
  void FullRedraw(void);
 

	
 
protected:
 
  /* void contentsMousePressEvent(QMouseEvent*);
 
  void contentsMouseMoveEvent(QMouseEvent*);
 
  void contentsMouseReleaseEvent(QMouseEvent*);*/
 
  void mousePressEvent(QMouseEvent*);
 
  void mouseMoveEvent(QMouseEvent*);
 
  void mouseReleaseEvent(QMouseEvent*);
 
  void wheelEvent(QWheelEvent *event);
 
  void scaleView(qreal scaleFactor);
 

	
 
  vector <CellItem *> getIntersectedCells(void);
 
  void insertNode(QPointF p);
 
  NodeItem *selectedNodeItem(QList<QGraphicsItem *> l) const;  
 

	
 
 signals:
 
  void status(const QString&);
 
  void MousePressed(void);
 
  void MouseReleased(void);
 
 protected:
 
  Mesh &mesh;
 

	
 
 private:
 
  //NodeItem* moving;
 
  SimItemBase *moving;
 
  QPointF moving_start;
 
    
 
  QGraphicsLineItem *intersection_line;
 
  bool rotation_mode;
 
  bool insert_mode;
 
  double rot_angle;
 
};
 

	
 
class Main : public Q3MainWindow, public MainBase {
 
  Q_OBJECT
 
	friend class ModelCatalogue; // needs to populate menu item models
 
    public:
 
  Main(QGraphicsScene&, Mesh&, QWidget* parent=0, const char* name=0, Qt::WFlags f=0);
 
  ~Main();
 
  virtual bool ShowCentersP(void) {return view->isItemChecked(com_id);}
 
  virtual bool ShowMeshP(void) {return view->isItemChecked(mesh_id);}
 
  virtual bool ShowBorderCellsP(void) {return view->isItemChecked(border_id);}
 
  virtual bool PausedP(void) {return run->isItemChecked(paused_id);}
 
  virtual bool ShowNodeNumbersP(void) {return view->isItemChecked(node_number_id);}
 
  virtual bool ShowCellNumbersP(void) {return view->isItemChecked(cell_number_id);}
 
  virtual bool ShowCellAxesP(void) {return view->isItemChecked(cell_axes_id);}
 
  virtual bool ShowCellStrainP(void) {return view->isItemChecked(cell_strain_id);}
 
  virtual bool MovieFramesP(void) {return view->isItemChecked(movie_frames_id);}
 
  virtual bool ShowBoundaryOnlyP(void) {return view->isItemChecked(only_boundary_id);}
 
  virtual bool ShowWallsP(void) {return view->isItemChecked(cell_walls_id);}
 
	virtual bool ShowApoplastsP(void) { return view->isItemChecked(apoplasts_id);}
 
  virtual bool ShowFluxesP(void) { return view->isItemChecked(fluxes_id); }
 
  virtual bool DynamicCellsP(void) { return options->isItemChecked(dyn_cells_id); }
 
  virtual bool RotationModeP(void) { return options->isItemChecked(rotation_mode_id); }
 
  virtual bool InsertModeP(void) { return options->isItemChecked(insert_mode_id); }
 
  virtual bool ShowToolTipsP(void) { return helpmenu->isItemChecked(tooltips_id); }
 
  virtual bool HideCellsP(void) { return view->isItemChecked(hide_cells_id); }
 
  void scale(double factor); 
 
  virtual double getFluxArrowsize(void) {
 
    return flux_arrow_size;
 
  }
 
  //void Save(const char *fname, const char *format);
 
  /*void StartGifAnim(QString fname);
 
    void SaveToGifAnim(void);
 
    void EndGifAnim(void);*/
 
    
 
  void FitCanvasToWindow();
 
  void FitLeafToCanvas(void);
 

	
 

	
 
  public slots:
 

	
 
  void help();
 
  void TimeStepWrap();
 
  //void scrollBy(int dx, int dy);
 
  void togglePaused();
 
  void setFluxArrowSize(int size);
 
  //void Divide(void);
 
  void RestartSim(void);
 
  //void toggleDoubleBuffer(void);
 
  void toggleShowCellCenters(void);
 
  void toggleShowNodes(void);
 
  void toggleShowBorderCells(void);
 
  void toggleShowFluxes(void);
 
  void toggleNodeNumbers(void);
 
  void toggleCellNumbers(void);
 
  void toggleCellAxes(void);
 
  void toggleCellStrain(void);
 
  void toggleShowWalls(void);
 
	void toggleShowApoplasts(void);
 
  void toggleDynCells(void);
 
  void toggleMovieFrames(void);
 
  void toggleLeafBoundary(void);
 
  void toggleHideCells(void);
 
  void print();
 
  void startSimulation(void);
 
  void stopSimulation(void);
 
  void RefreshInfoBar(void);
 

	
 
  void EnterRotationMode(void) {
 

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

	
 
      // Exit rotation mode if mouse is clicked
 
      connect(editor, SIGNAL(MousePressed()), this, SLOT(ExitRotationMode()));
 
    }
 
  
 
  }
 
  void ExitRotationMode(void) { 
 
    UserMessage("Exited rotation mode.",2000);
 

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

	
 
  virtual void UserMessage(QString message, int timeout=0);
 
  void Refresh(void) { Plot(); }
 
  void PauseIfRunning(void);
 
  void ContIfRunning(void);
 
  virtual void XMLReadSettings(xmlNode *settings);
 
   
 
  private slots:
 
  void aboutQt();
 
  void newView();
 
  void EditParameters();
 
  void readStateXML();
 
  int readStateXML(const char *filename, bool geometry = true, bool pars=true, bool simtime = true);
 
  void readNextStateXML();
 
  void readPrevStateXML();
 
  void readFirstStateXML();
 
  void readLastStateXML();
 
  void saveStateXML();
 
  void snapshot();
 
  void savePars();
 
  void readPars();
 
  void clear();
 
  void init();
 
  virtual void CutSAM() { MainBase::CutSAM(); Refresh();}
 
/*   void cellmonitor() { */
 
/*     PlotDialog *plot = new PlotDialog(this); */
 
/*     cerr << "Attempting to launch a cell monitor\n"; */
 
/*   } */
 
  
 
  //void addPolygon();
 
  //void addLine();
 

	
 
  void enlarge();
 
  void shrink();
 
  void zoomIn();
 
  void zoomOut();
 
  
 
	>
 
  void CleanMesh();
 
	void CleanMeshChemicals(void);
 
	void CleanMeshTransporters(void);
 
	
 
  void RandomizeMesh();
 

	
 
 signals:
 
  void SimulationDone(void);
 
  void ParsChanged(void);
 
  
 
 protected:
 
  Mesh &mesh;
 
  
 
 private:
 
  NodeSet *node_set;
 
  FigureEditor *editor;
 
  //QCanvas& canvas;
 
  Q3PopupMenu* options;
 
  Q3PopupMenu *view;
 
  Q3PopupMenu *run;
 
	QMenu *modelmenu;
 
  Q3PopupMenu *helpmenu;
 

	
 
  QPrinter* printer;
 
  const QDir *working_dir;
 
  QString currentFile;
 
  //  toggle item states 
 
  int dbf_id; // options->Double Buffer
 
  int com_id; // view->Show centers
 
  int mesh_id; // view->Show mesh
 
  int node_number_id; // view->Show Node numbers
 
  int cell_number_id; // view->Show Cell numbers
 
  int border_id; // view->Show border cells
 
  int paused_id; // run->Simulation paused
 
  int cell_axes_id; // view->Show cell axes
 
  int cell_strain_id; // view->Show cell strain
 
  int only_boundary_id; // view ->Show only leaf boundary
 
  int cell_walls_id; // view -> Show transporters
 
	int apoplasts_id; // view -> Show apoplasts
 
  int tooltips_id; // help -> Show Cell Info
 
  int hide_cells_id; // view->Hide Cells
 
  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
src/mesh.cpp
Show inline comments
 
@@ -1507,772 +1507,786 @@ 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
 
  cerr << "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;
 
  set<int> boundary_node_owners; // This is a list of the current boundary node's owners' Ids
 
  vector<int> neighborIds; // A list of the current boundary node's owners' 2nd neighbor Ids
 
  vector<set<int> *>  nodeOwners; // A vector of set pointers where each set contains the owner Ids of the nodes in the neighborIds list.
 
  vector<int> intersection; // set intersection result
 

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

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

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

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

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

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

	
 
      break;
 
    }
 
  }
 

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

	
 
  return next_boundary_node;
 
}
 

	
 

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

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

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

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

	
 
  Matrix rotmat;
 

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

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

	
 

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

	
 
}
 

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

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

	
 

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

	
 

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

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

	
 
/*! This member function deletes all walls connected to two dead cells from the mesh.
 
  It should be called before the Cells are actually removed.
 
  If the cell is connect to one dead cell only, that reference is substituted for a reference 
 
  to the boundary polygon.
 
*/
 
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, const vector<double> &clean_transporters) {
 
  
 
  if (clean_chem.size()!=(unsigned)Cell::NChem() || clean_transporters.size()!=(unsigned)Cell::NChem()) {
 
    throw "Run time error in Mesh::CleanChemicals: size of clean_chem and clean_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,clean_chem[i]);
 
    }
 
    (*c)->SetNewChemToChem();
 

	
 
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]);
 
    }
 
  }
 
  
 
	
 
	// 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++) {
 
    //(*cr)(*c, &(derivs[i]));
 
	  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];
 
  }
 

	
 
  // Amount of PIN1
 
  //clean_chem[1] = 0.;
 
  
 
  CleanChemicals(clean_chem, clean_transporters);
 
	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?)
 

	
 
        #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.);
 
	}
 
}
 

	
 

	
src/mesh.h
Show inline comments
 
@@ -32,449 +32,450 @@
 
#include <queue>
 
#include <iterator>
 
#include <functional>
 
#ifdef QTGRAPHICS
 
#include <QGraphicsScene>
 
#endif
 
#include "cell.h"
 
#include "node.h"
 
#include "simplugin.h"
 
#include <QVector>
 
#include <QPair>
 

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

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

	
 

	
 
class Mesh {
 
	
 
	friend class Cell;
 
	friend class Node;
 
	friend class FigureEditor;
 
	
 
public: 
 
	Mesh(void) {
 
		// Make sure the reserved value is large enough if a cell is added
 
		// in "Divide" when the capacity is insufficient, "cells" might be
 
		// relocated including the current Cell (i.e. the value of *this)
 
		// calling "Mesh::IncreaseCapacityIfNecessary" (from another
 
		// object than Cell, e.g. Mesh) before entering Divide will solve
 
		// this issue (solved now).
 
		cells.reserve(2);
 
		nodes.reserve(500);
 
		
 
		//boundary_polygon = new BoundaryPolygon();
 
		
 
		time = 0.;
 
		plugin = 0;
 
	};
 
	~Mesh(void) {
 
		delete boundary_polygon;
 
		/* if (plugin)
 
			delete plugin;*/
 
	};
 
	
 
	void Clean(void);
 
	//void Plane(int xwidth, int ywidth, int nx, int ny, bool randomP=false);
 
	Cell &EllipticCell(double xc, double yc, double ra, double rb, int nnodes=10, double rotation=0);
 
	Cell &CircularCell(double xc, double yc, double r, int nnodes=10) {
 
		return EllipticCell(xc, yc, r, r, nnodes, 0);
 
	}
 
	Cell &LeafPrimordium(int n, double pet_length);
 
	Cell &LeafPrimordium2(int n);
 
	Cell *RectangularCell(const Vector ll, const Vector ur, double rotation = 0);
 
	void CellFiles(const Vector ll, const Vector ur);
 
	
 
	/*  void GMVoutput(ostream &os, 
 
	 const char *codename=0, const char *codever=0,
 
	 const char *comments=0);*/
 
	//void RandPoints(int npoints);
 
	
 
	inline Cell &getCell(int i) {
 
		if ((unsigned)i<cells.size())
 
			return *cells[i];
 
		else {
 
			cerr << i << endl;
 
			cerr << "size is " << cells.size() << endl;
 
			abort();
 
			//	throw("Index out of range in Mesh::getCell");
 
		}
 
	}
 
	
 
	inline Node &getNode(int i) {
 
		//if (i >= nodes.size() || i < 0) {
 
		//  cerr << "Mesh::getNode: Warning. Index " << i << " out of range.\n";
 
		// }
 
		return *nodes[i];    
 
	}
 
	
 
	//double Diffusion(void);
 
	inline int size(void) {
 
		return cells.size();
 
	}
 
	inline int nnodes(void) {
 
		return nodes.size();
 
	}
 
	//void SortNBLists(void);
 
	
 
	/*template<class Op> void LoopCells(Op f) {
 
	 for (vector<Cell>::iterator i=cells.begin();
 
	 i!=cells.end();
 
	 i++) {
 
	 f(*i); 
 
	 }
 
	 }*/
 
	
 
	/*! \brief Calls function f for all Cells f.
 
	 
 
	 Using this template requires some fiddling with function adaptors bind2nd and mem_fun_ref.
 
	 
 
	 Example usage for calling a member function on each cell:
 
	 
 
	 mesh.LoopCells( bind2nd (mem_fun_ref( &Cell::DrawDiffEdges), &canvas ) );
 
	 
 
	 This calls Cell's member function DrawDiffEdges, taking one
 
	 argument canvas, on all Cell objects in the current Mesh.
 
	 
 
	 */
 
	template<class Op> void LoopCells(Op f) {
 
		for (vector <Cell *>::iterator i=cells.begin();
 
			 i!=cells.end();
 
			 i++) {
 
			f(**i);
 
		}
 
		//for_each(cells.begin(),cells.end(),f);
 
	}
 
	
 
	template<class Op> void LoopWalls(Op f) {
 
		for (list <Wall *>::iterator i=walls.begin();
 
			 i!=walls.end();
 
			 i++) {
 
			f(**i);
 
		}
 
	}
 
	
 
	// if the amount of cells might increase, during looping, use this template
 
	template<class Op> void LoopCurrentCells(Op f) {
 
		vector<Cell *> current_cells = cells;
 
		for (vector <Cell *>::iterator i=current_cells.begin();
 
			 i!=current_cells.end();
 
			 i++) {
 
			f(**i);
 
			
 
		}
 
		//for_each(cells.begin(),cells.end(),f);
 
	}
 
	
 
	template<class Op> void LoopNodes(Op f) {
 
		for (vector<Node *>::iterator i=nodes.begin();
 
			 i!=nodes.end();
 
			 i++) {
 
			f(**i); 
 
		}
 
	}
 
	
 
	template<class Op> void RandomlyLoopNodes(Op f) {
 
		
 
		MyUrand r(shuffled_nodes.size());
 
		random_shuffle(shuffled_nodes.begin(),shuffled_nodes.end(),r);
 
		
 
		for (vector<Node *>::const_iterator i=shuffled_nodes.begin();
 
			 i!=shuffled_nodes.end();
 
			 i++) {
 
			f(*shuffled_nodes[*i]);
 
		}
 
		
 
	}
 
	
 
	template<class Op> void RandomlyLoopCells(Op f) {
 
		
 
		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;
 
			}
 
		}
 
	}
 
/*	template<class Op1, class Cont> void ExtractFromCells(Op1 f, Cont res) {
 
		for (vector<Cell>::iterator i=cells.begin();
 
			 i!=cells.end();
 
			 i++) {
 
			*(res++) = ( f(*i) );
 
		}
 
	}*/
 
	
 
	// Apply "f" to cell i
 
	// i.e. this is an adapter which allows you to call a function
 
	// operating on Cell on its numeric index index
 
	template<class Op> void cell_index_adapter(Op f,int i) {
 
		f(cells[i]);
 
	}
 
	
 
	double DisplaceNodes(void);
 
	
 
	void BoundingBox(Vector &LowerLeft, Vector &UpperRight);
 
	int NEqs(void) {     int nwalls = walls.size();
 
		int ncells =cells.size();
 
		int nchems = Cell::NChem();
 
		
 
		// two eqs per chemical for each walls, and one eq per chemical for each cell
 
		// This is for generality. For a specific model you may optimize
 
		// this by removing superfluous (empty) equations.
 
		int neqs = 2 * nwalls * nchems + ncells * nchems;
 
		
 
		return neqs;
 
	}
 
	void IncreaseCellCapacityIfNecessary(void) {
 
		
 
		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();
 
		}
 
		//copy (node_insertion_queue.begin(),node_insertion_queue.end(),ostream_iterator<Edge>(cerr, " "));
 
	}
 
	
 
	void InsertNodes(void) {
 
		// insert the nodes in the insertion queue
 
		while (!node_insertion_queue.empty()) {
 
			
 
			//cerr << node_insertion_queue.front() << endl;
 
			InsertNode(node_insertion_queue.front());
 
			node_insertion_queue.pop();
 
		}
 
		
 
	}
 
	
 
	void Clear(); 
 
	
 
	//  template<class ReactFunction> ReactDiffuse(const double D, ReactFunction& react) {
 
	void ReactDiffuse( double delta_t = 1 );
 
	//void Diffuse(const double D);
 
	double SumChemical(int ch);
 
	void SetChemical(int ch, double value) {
 
		for (vector<Cell *>::iterator c=cells.begin();
 
			 c!=cells.end();
 
			 c++) {
 
			(*c)->chem[ch]=value;
 
		}
 
	}
 
	
 
	// used for interacing with ODE-solvers (e.g. NRCRungeKutta)
 
	void setValues(double x, double *y);
 
	double *getValues(int *neqs);
 
	void Derivatives(double *derivs);
 
#ifdef QTGRAPHICS
 
	inline void DrawBoundary(QGraphicsScene *c) {
 
		boundary_polygon->Draw(c);
 
	}
 
	void DrawNodes(QGraphicsScene *c) const;
 
	
 
#endif
 
	double max_chem;
 
	
 
	void XMLSave(const char *docname, xmlNode *settings=0) const;
 
	void XMLRead(const char *docname, xmlNode **settings=0, bool geometry = true, bool pars = true, bool simtime = true);
 
	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, const vector<double> &clean_transporters);
 
	void CleanChemicals(const vector<double> &clean_chem);
 
	void CleanTransporters(const vector<double> &clean_transporters);
 
	void RandomizeChemicals(const vector<double> &max_chem, const vector<double> &max_transporters);
 
	inline double getTime(void) const { return time; }
 
	string getTimeHours(void) const; 
 
	inline void setTime(double t) { time = t; }
 
	double CalcProtCellsWalls(int ch) const;  
 
	void SettoInitVals(void);
 
	QVector<qreal> VertexAngles(void);
 
	QVector< QPair<qreal,int> > VertexAnglesValues(void);
 
	void SetSimPlugin(SimPluginInterface *new_plugin) {
 
		/* if (plugin) 
 
			delete plugin;*/
 
		plugin=new_plugin;
 
	}
 
	QString ModelID(void) { return plugin?plugin->ModelID():QString("undefined"); }
 
	void StandardInit(void);	
 

	
 
	Node* findNextBoundaryNode(Node*);
 

	
 
private:
 
	
 
	// Data members
 
	vector<Cell *> cells;
 
	vector<Node *> nodes;
 
	list<Wall *> walls; // we need to erase elements from this container frequently, hence a list.
 
public:
 
	vector<NodeSet *> node_sets;
 
private:
 
	vector<Node *> shuffled_nodes;
 
	vector<Cell *> shuffled_cells;
 
	unique_queue<Edge> node_insertion_queue;
 
	BoundaryPolygon *boundary_polygon;
 
	double time;
 
	SimPluginInterface *plugin;
 
	
 
	// Private member functions
 
	void AddNodeToCell(Cell *c, Node *n, Node *nb1 , Node *nb2);
 
	void AddNodeToCellAtIndex(Cell *c, Node *n, Node *nb1 , Node *nb2, list<Node *>::iterator ins_pos);
 
	void InsertNode(Edge &e);
 
	inline Node *AddNode(Node *n) {
 
		nodes.push_back(n);
 
		shuffled_nodes.push_back(n);
 
		n->m=this;
 
		return n;
 
	}
 
	
 
	inline Cell *AddCell(Cell *c) {
 
		cells.push_back(c);
 
		shuffled_cells.push_back(c);
 
		//cerr << "Shuffled cell indices:  ";
 
		/*copy(shuffled_cells.begin(),shuffled_cells.end(),ostream_iterator<int>(cerr," "));
 
		 cerr << endl;*/
 
		c->m=this;
 
		return c;
 
	}
 
	
 
	//int Delaunay(void);
 
	void CircumCircle(double x1,double y1,double x2,double y2,double x3,double y3,
 
					  double *xc,double *yc,double *r);
 
	
 
	
 
	// void RenumberCells(void);
 
	
 
};
 
#endif
0 comments (0 inline, 0 general)