diff --git a/src/TriangleMesh.cpp b/src/TriangleMesh.cpp index 07d4cddbe16763fb40b303f7fdf06d11d6dba040..01029869cb6a5de60405bd42a5886b41243c6a41 100644 --- a/src/TriangleMesh.cpp +++ b/src/TriangleMesh.cpp @@ -582,6 +582,9 @@ int ActiveMesh::ImportVTK_Ftree(const char *filename,unsigned int idx, filoMesh->norm.clear(); } + //resets the branchID_to_FtreeIndices mapping + tipOffsets.clear(); + //setup a list of indices that were populated from this file, //the list becomes interesting only if the filopodium branches //(the list is actually a flag-array.... lazy programmer) @@ -731,13 +734,13 @@ int ActiveMesh::ImportVTK_Ftree(const char *filename,unsigned int idx, //temporal storage of radii which are given for every point //(but we store them for beginning of every skeleton segment) - std::vector<float> radiiAtPoints; - radiiAtPoints.reserve(itemCount); + std::vector<float> tmpValAtPoints; + tmpValAtPoints.reserve(itemCount); //read the radii while (itemCount > 0 && file >> x) { - radiiAtPoints.push_back(x*radiusCorrection); + tmpValAtPoints.push_back(x*radiusCorrection); //std::cout << "reading radius: " << x*radiusCorrection << "\n"; --itemCount; @@ -745,11 +748,39 @@ int ActiveMesh::ImportVTK_Ftree(const char *filename,unsigned int idx, //now, store the radii per skeleton segments for (unsigned int qq=0; qq < filoMesh->segFromPoint.size(); ++qq) - filoMesh->segFromRadius.push_back(radiiAtPoints[filoMesh->segFromPoint[qq]]); + filoMesh->segFromRadius.push_back(tmpValAtPoints[filoMesh->segFromPoint[qq]]); + tmpValAtPoints.clear(); + + //read branch IDs, i.e. POINT_DATA header + file >> tmp >> itemCount; + if (tmp[0] != 'P' + || tmp[1] != 'O' + || tmp[2] != 'I' + || tmp[3] != 'N' + || tmp[4] != 'T' + || tmp[5] != '_' + || tmp[6] != 'D' + || tmp[7] != 'A') { file.close(); return(8); } + file.ignore(10240,'\n'); + file.ignore(10240,'\n'); //ignore SCALARS.. + file.ignore(10240,'\n'); //ignore LOOKUP_TABLE + + //read the IDs + while (itemCount > 0 && file >> x) + { + tmpValAtPoints.push_back(x); + //std::cout << "reading ID: " << x << "\n"; + + --itemCount; + } - radiiAtPoints.clear(); file.close(); + //note the first binding: the main branch + tipOffsets[(int)tmpValAtPoints.front()]=idx; +#ifdef DEBUG_BRANCHING + std::cout << "detected main branchID=" << tmpValAtPoints.front() << "\n"; +#endif //now detect offspring branches, test if segIndex is candidate for a branching point //on the current filopodium (which is referenced with filoMesh and idx) @@ -797,6 +828,10 @@ int ActiveMesh::ImportVTK_Ftree(const char *filename,unsigned int idx, populatedIndices[idx]=true; Ftree[idx].parent=(signed)ret_idx; + tipOffsets[ (int)tmpValAtPoints[filoMesh->segFromPoint[segIndex]] ]=idx; +#ifdef DEBUG_BRANCHING + std::cout << "detected offspring branchID=" << tmpValAtPoints[filoMesh->segFromPoint[segIndex]] << "\n"; +#endif //copy the positions vector Ftree[idx].fPoints=filoMesh->fPoints; @@ -1357,6 +1392,38 @@ void ActiveMesh::RenderOneTimeTexture(const i3d::Image3d<i3d::GRAY16>& mask, } +void ActiveMesh::UpdateMeshBBox(Vector3F& min,Vector3F& max) +{ + //first, for the cell body + for (unsigned int i=0; i < Pos.size(); ++i) + { + min.x=std::min(min.x,Pos[i].x); + min.y=std::min(min.y,Pos[i].y); + min.z=std::min(min.z,Pos[i].z); + + max.x=std::max(max.x,Pos[i].x); + max.y=std::max(max.y,Pos[i].y); + max.z=std::max(max.z,Pos[i].z); + } + + //second, for all filopodia + for (size_t f=0; f < Ftree.size(); ++f) + { + const mesh_t& filoMesh=Ftree[f]; + for (unsigned int i=0; i < filoMesh.Pos.size(); ++i) + { + min.x=std::min(min.x,filoMesh.Pos[i].x); + min.y=std::min(min.y,filoMesh.Pos[i].y); + min.z=std::min(min.z,filoMesh.Pos[i].z); + + max.x=std::max(max.x,filoMesh.Pos[i].x); + max.y=std::max(max.y,filoMesh.Pos[i].y); + max.z=std::max(max.z,filoMesh.Pos[i].z); + } + } +} + + void ActiveMesh::CenterMesh(const float safeConstant) { //calc geom. centre, @@ -1400,40 +1467,6 @@ void ActiveMesh::CenterMesh(const float safeConstant) } -void ActiveMesh::ScaleMesh(const Vector3F& scale) -{ - //cell body - for (unsigned int i=0; i < Pos.size(); ++i) - { - Pos[i].x*=scale.x; - Pos[i].y*=scale.y; - Pos[i].z*=scale.z; - } - - //filopodia - for (size_t f=0; f < Ftree.size(); ++f) - { - mesh_t& filoMesh=Ftree[f]; - for (unsigned int i=0; i < filoMesh.Pos.size(); ++i) - { - filoMesh.Pos[i].x*=scale.x; - filoMesh.Pos[i].y*=scale.y; - filoMesh.Pos[i].z*=scale.z; - } - for (unsigned int i=0; i < filoMesh.fPoints.size(); ++i) - { - filoMesh.fPoints[i].x*=scale.x; - filoMesh.fPoints[i].y*=scale.y; - filoMesh.fPoints[i].z*=scale.z; - } - for (unsigned int i=0; i< filoMesh.segFromRadius.size(); i++) - { - filoMesh.segFromRadius[i] *= 80.f; - } - } -} - - void ActiveMesh::TranslateMesh(const Vector3F& shift) { //cell body diff --git a/src/TriangleMesh.h b/src/TriangleMesh.h index 5ecec9c564b892485fb2de7cc241e62baac0be7c..977295e622c160c36ac70f692986d90455f3149c 100644 --- a/src/TriangleMesh.h +++ b/src/TriangleMesh.h @@ -2,6 +2,7 @@ #define __TRIANGLEMESH__FOR_MT__ #include <vector> +#include <map> #include <i3d/image3d.h> #include "params.h" @@ -81,12 +82,19 @@ class ActiveMesh int ImportVTK(const char* filename); int ImportVTK_Volumetric(const char* filename,bool saveAlsoTetrahedra=false); + ///a binding map to be reset with every ImportVTK_Ftree(); + ///this map connects branchIDs found in the VTK with + ///the indices added into the this->Ftree + std::map<int,unsigned int> tipOffsets; + /** * Import filopodium from file, and save it at specific index (replacing what was there); * if the index is 999999, just append (to the ActiveMesh::Ftree array). * * This one saves the skeleton information (fPoints,segFrom/ToPoint,segFromRadius attributes) * and calls PopulateSurfTriangles_Ftree() to obtain a mesh. + * + * This one also resets the this->tipOffsets. */ int ImportVTK_Ftree(const char* filename,unsigned int idx,const float stretch=1.f,bool resetMesh=true); @@ -143,12 +151,20 @@ class ActiveMesh bool DotsFirstRun(void) { return (dots.size() == 0); } - ///mesh rigid-manipulation functions to convert it from - ///Dima's world into real microns-floating-point coordinates - ///such that the cell appears approx. in the middle of the output images - void ScaleMesh(const Vector3F& scale); + ///if needed, it shifts all mesh coordinates by the \e shift vector void TranslateMesh(const Vector3F& shift); + /** + * scans all mesh coordinates and checks if some falls + * outside the \e min <-> \e max interval, and updates + * (increases) the interval in the respective coordinate axis. + * + * NB: If you initiate \e min and \e max with, for instance, + * mesh body centre, this update will give you current bounding + * box of the mesh. + */ + void UpdateMeshBBox(Vector3F& min,Vector3F& max); + /** * sets the optimal size and translation vectors (defined below), * it does not alter the mesh @@ -162,6 +178,7 @@ class ActiveMesh ///optimal output image size in microns Vector3F meshPlaygroundSize; ///default mesh translation to appear approx. in the output image centre + ///or, it can be considered as an image offset (to avoid translating the mesh) Vector3F meshShift; //the following functions are all defined in graphics.cpp diff --git a/src/graphics.cpp b/src/graphics.cpp index 87014818912fec376dd49c2d5e1477242c96884b..61ace5bd40cd79f2925822af79a7ff33184834b4 100644 --- a/src/graphics.cpp +++ b/src/graphics.cpp @@ -57,7 +57,7 @@ bool showWholeMeshEdges=false; std::string path; int ID; int frameNo=0; -bool LoadNewMesh(const char* path,const int ID,const int fileNo); +bool LoadNewMesh(const char* path,const int ID,const int fileNo,const bool keepTipTrajectories=false); int RenderMesh(int fileNo); ///manage \e count steps of the simulation and then print and draw diff --git a/src/main_Compactor.cpp b/src/main_Compactor.cpp index bbc1388d382036292534b4cf73cace0f803a5aaf..71898e738e8ef4ac50afa8de2b15a2738479def0 100644 --- a/src/main_Compactor.cpp +++ b/src/main_Compactor.cpp @@ -17,7 +17,7 @@ void ParamsSetup(void); // ActiveMesh mesh; -bool LoadNewMesh(const char* path,const int ID,const int fileNo); +bool LoadNewMesh(const char* path,const int ID,const int fileNo,const bool keepTipTrajectories=false); int main(int argc,char **argv) { @@ -123,7 +123,7 @@ void ParamsSetup(void) } -bool LoadNewMesh(const char* path,const int ID,const int fileNo) +bool LoadNewMesh(const char* path,const int ID,const int fileNo,const bool keepTipTrajectories) { //this function is here only because the graphics.cpp module references it //but graphics is not used in this module at all... @@ -132,5 +132,6 @@ bool LoadNewMesh(const char* path,const int ID,const int fileNo) int a=(int)path[0]; a+=fileNo; a+=ID; + a+=(keepTipTrajectories)? 1 : 0; return(true); } diff --git a/src/main_Generator.cpp b/src/main_Generator.cpp index acc5eb03e18ee001578325dc54c23807dd34b855..966a1bc2dd78e88f868af3977003a218312b5373 100644 --- a/src/main_Generator.cpp +++ b/src/main_Generator.cpp @@ -19,9 +19,29 @@ void ParamsSetup(void); ActiveMesh mesh; //for filopodia tip tracking: -std::vector< std::vector<int> > tipOffsets; +// GM addresses filopodia branches with pairs: filoTreeID + branchID; +// we linearize them with tipIndex() (e.g., as filoTreeID*100+branchID); +// this is the first index (primary key) in tipOffsets; +// the second index (secondary key) is time point and +// the value is actually a pixel offset (encoding a tip position) +// +//time-course (vector index) of pixel offsets (vector value) +class timeVector: public std::vector<int> +{ + public: + void Init(const size_t length=200) + { this->insert(this->end(),length,-1); } +}; +// +//this one holds the entire time-lapse of pixel offsets of all filopodia tips +//use tipIndex() below to address filopodia branches +std::map<int,timeVector> tipOffsets; +// +//use exclusively this one to address filopodia branches in tipOffsets above +int tipIndex(const int filoID,const int branchID) +{ return (filoID*100 +branchID); } -bool LoadNewMesh(const char* path,const int ID,const int fileNo); +bool LoadNewMesh(const char* path,const int ID,const int fileNo,const bool keepTipTrajectories=false); int RenderMesh(const char* path,const int ID,int fileNo); int main(int argc,char **argv) @@ -53,32 +73,59 @@ int main(int argc,char **argv) //I'm called as generator/simulator, init the situation... ParamsSetup(); - //for filopodia tip tracking: - //container for 200 (all possible) filopodia tips, - //initiated for 200 timeframes with position undefined (yet) - tipOffsets.reserve(200); - for (unsigned int qq=0; qq < 200; ++qq) - tipOffsets.push_back( std::vector<int>(200,-1) ); - - //indicator that the mesh translation has not been decided yet - mesh.meshShift.x=-4567.f; + std::cout << "FIRST RUN: reading all meshes to figure out minimal bounding box.\n"; + //doubling iteration variables not to loose their values + int ii(i); //starting index + int fframesToGoHome(framesToGoHome); //how many indices to read + Vector3F minBB,maxBB; //bounding box corners - while (LoadNewMesh(argv[1],ID,i) && (framesToGoHome > 0)) + while (LoadNewMesh(argv[1],ID,ii) && (fframesToGoHome > 0)) { - std::cout << "mesh: #" << i << "\n"; + std::cout << "mesh: #" << ii << "\n"; std::cout << "vertices #: " << mesh.Pos.size() << "\n"; std::cout << "triangles #: " << mesh.ID.size()/3 << "\n"; std::cout << "tetrahedra #: " << mesh.VolID.size()/4 << "\n"; std::cout << "normals #: " << mesh.norm.size() << "\n"; - std::cout << "filopodia #: " << mesh.Ftree.size() << "\n"; + //std::cout << "filopodia #: " << mesh.Ftree.size() << "\n"; for (size_t f=0; f < mesh.Ftree.size(); ++f) { - std::cout << f << ": vertices #: " << mesh.Ftree[f].Pos.size() << "\n"; - std::cout << f << ": triangles #: " << mesh.Ftree[f].ID.size()/3 << "\n"; - std::cout << f << ": normals #: " << mesh.Ftree[f].norm.size() << "\n"; + if (mesh.Ftree[f].Pos.size() > 0) + { + std::cout << f << ": vertices #: " << mesh.Ftree[f].Pos.size() << "\n"; + std::cout << f << ": triangles #: " << mesh.Ftree[f].ID.size()/3 << "\n"; + std::cout << f << ": normals #: " << mesh.Ftree[f].norm.size() << "\n"; + } } + //update the current bounding box + if (i == ii) + { + //first run, init BB corners + minBB=mesh.Pos[0]; + maxBB=mesh.Pos[0]; + } + mesh.UpdateMeshBBox(minBB,maxBB); + + ++ii; + --fframesToGoHome; + } + + //given the discovered bounding box valid for the whole sequence, and given + //that we DO want to keep mesh coordinates even in the produced images, + //we have to utilize the images _offset_ attribute, instead of + //translating all mesh points, to assure the meshes appear within + //the produced images + mesh.meshShift=minBB -Vector3F(1.0f); + mesh.meshPlaygroundSize=(maxBB-minBB) +Vector3F(2.0f); + //NB: We also introduce 1um thick border around the mesh + std::cout << "corners of a detected bounding box (with 1um thick border):\n"; + std::cout << "[" << minBB.x << "," << minBB.y << "," << minBB.z << "] <-> [" + << maxBB.x << "," << maxBB.y << "," << maxBB.z << "] in microns\n"; + + std::cout << "SECOND RUN: reading all meshes to conduct the texture simulation and rendering.\n"; + while (LoadNewMesh(argv[1],ID,i,true) && (framesToGoHome > 0)) + { RenderMesh(argv[2],ID,i); ++i; --framesToGoHome; @@ -86,12 +133,14 @@ int main(int argc,char **argv) //report the tip trajectories std::ofstream tFile("tip_trajectories.txt"); - for (unsigned int qq=0; qq < mesh.GetFilopodiaNumber(); ++qq) + std::map<int,timeVector>::const_iterator tipIter=tipOffsets.begin(); + while (tipIter != tipOffsets.end()) { - tFile << qq << ":"; + tFile << tipIter->first << ":"; for (int t=0; t < i; ++t) - tFile << tipOffsets[qq][(unsigned)t] << ","; + tFile << tipIter->second.at((unsigned)t) << ","; tFile << "\n"; + ++tipIter; } tFile.close(); @@ -147,7 +196,7 @@ void ParamsSetup(void) } -bool LoadNewMesh(const char* path,const int ID,const int fileNo) +bool LoadNewMesh(const char* path,const int ID,const int fileNo,const bool keepTipTrajectories) { char fn[1024]; @@ -174,10 +223,33 @@ bool LoadNewMesh(const char* path,const int ID,const int fileNo) { ++filoNo; sprintf(fn,"%s/ID%d/ID%d_t%03d_fTree%02d.vtk",path,ID,ID,fileNo,filoNo); - std::cout << "reading filopodium: " << fn << "\n"; retval=mesh.ImportVTK_Ftree(fn,999999); - } while (retval == 0); + if (retval != 1) std::cout << "reading filopodium: " << fn << "\n"; + if (retval == 0 && keepTipTrajectories == true) + { + //managed to import filopodium (possibly with its offspring branches) + //remember at what indices in mesh.Ftree are these stored + //(as we cannot yet remember directly the pixel offset, we at least + //remember index within mesh.Ftree and translate to pixel offset later) + // + //iterate over the internal mapping (just_branchID -> Ftree indices) + std::map<int,unsigned int>::const_iterator iterTips=mesh.tipOffsets.begin(); + while (iterTips != mesh.tipOffsets.end()) + { + const int idx=tipIndex(filoNo,iterTips->first); + if (tipOffsets[idx].size() == 0) + { + //we have found a new pair filoID+branchID + tipOffsets[idx].Init(); + } + tipOffsets[idx].at((unsigned)fileNo)=(signed)iterTips->second; + + ++iterTips; + } + } + } while (retval < 2 && filoNo < 100); + //NB: retval == 0 when read successfully; == 1 when file open error //report errors except for "cannot open file" if (retval > 1) @@ -189,13 +261,7 @@ bool LoadNewMesh(const char* path,const int ID,const int fileNo) //remove last filopodium mesh (which is usually empty...) mesh.DiscardLastEmptyFilopodiumObject(); - std::cout << "loaded mesh #" << fileNo << " (with " << filoNo-1 << " filopodia)\n"; - - //position the mesh somewhat inside the scene - //first run? - if (mesh.meshShift.x == -4567.f) mesh.CenterMesh(); - //translate... - mesh.TranslateMesh(mesh.meshShift); + std::cout << "loaded mesh #" << fileNo << "\n"; //keep (by rotating) vertex positions mesh.RotateVolPos(); @@ -210,14 +276,12 @@ int RenderMesh(const char* path,const int ID,int fileNo) { //setup isotropic(!) image for mask-output of the simulated cell i3d::Image3d<i3d::GRAY16> mask; - mask.SetOffset(i3d::Offset(0.0,0.0,0.0)); + mask.SetOffset(i3d::Offset(mesh.meshShift.x,mesh.meshShift.y,mesh.meshShift.z)); mask.SetResolution(i3d::Resolution(8.0,8.0,8.0)); //use "optimal" calculated size mask.MakeRoom((size_t)(mesh.meshPlaygroundSize.x*8.0f), (size_t)(mesh.meshPlaygroundSize.y*8.0f), (size_t)(mesh.meshPlaygroundSize.z*8.0f)); - //over-ride size: - //mask.MakeRoom(220,220,176); mask.GetVoxelData()=0; //renders the isotropic mask into the image @@ -374,14 +438,23 @@ int RenderMesh(const char* path,const int ID,int fileNo) const float xOff=mask.GetOffset().x; const float yOff=mask.GetOffset().y; const float zOff=mask.GetOffset().z; - for (unsigned int i=0; i < mesh.GetFilopodiaNumber(); ++i) + + //scan over all branches we recognize at this time-point + std::map<int,timeVector>::iterator tipIter=tipOffsets.begin(); + while (tipIter != tipOffsets.end()) { - const Vector3FC& realPos=mesh.Ftree[i].fPoints[mesh.Ftree[i].segToPoint.back()]; - //get pixel coordinate - const size_t x=size_t((realPos.x-xOff) *xRes); - const size_t y=size_t((realPos.y-yOff) *yRes); - const size_t z=size_t((realPos.z-zOff) *zRes); - tipOffsets[i][(unsigned)fileNo]=(int)mask.GetIndex(x,y,z); + //if there is a record for the present time-point, translate it + if (tipIter->second.at((unsigned)fileNo) > -1) + { + const unsigned int i=(unsigned)tipIter->second.at((unsigned)fileNo); + const Vector3FC& realPos=mesh.Ftree[i].fPoints[mesh.Ftree[i].segToPoint.back()]; + //get pixel coordinate + const size_t x=size_t((realPos.x-xOff) *xRes); + const size_t y=size_t((realPos.y-yOff) *yRes); + const size_t z=size_t((realPos.z-zOff) *zRes); + tipIter->second.at((unsigned)fileNo)=(int)mask.GetIndex(x,y,z); + } + ++tipIter; } return(0); diff --git a/src/main_Pressurator.cpp b/src/main_Pressurator.cpp index 1dc72c4b8f868738f70e90d9ae24761f2fd41279..ae360f503e9e575ccebdb62d1c21a192d2be7b06 100644 --- a/src/main_Pressurator.cpp +++ b/src/main_Pressurator.cpp @@ -35,7 +35,7 @@ void ParamsSetup(void); ActiveMesh mesh; Vector3F sceneRes(8.f); //make isotropic resolution at 8 px/um -bool LoadNewMesh(const char* path,const int ID,const int fileNo); +bool LoadNewMesh(const char* path,const int ID,const int fileNo,const bool keepTipTrajectories=false); int PnInitArray(const std::string& fileName); int PnInitArray(i3d::Vector3d<size_t> const &size, const size_t frames, const std::string& fileName); @@ -595,7 +595,7 @@ int PnGetMeNonrigidHints(const float stretch,const size_t frames,i3d::Image3d<fl } -bool LoadNewMesh(const char* path,const int ID,const int fileNo) +bool LoadNewMesh(const char* path,const int ID,const int fileNo,const bool keepTipTrajectories) { //this function is here only because the graphics.cpp module references it //but graphics is not used in this module at all... @@ -604,5 +604,6 @@ bool LoadNewMesh(const char* path,const int ID,const int fileNo) int a=(int)path[0]; a+=fileNo; a+=ID; + a+=(keepTipTrajectories)? 1 : 0; return(true); } diff --git a/src/main_Vizualizator.cpp b/src/main_Vizualizator.cpp index f1b79d71fcf6213eb7df57f152e8b30720f44f55..aa7b48370428d08e9b54b4f45f65aaf80632ca24 100644 --- a/src/main_Vizualizator.cpp +++ b/src/main_Vizualizator.cpp @@ -19,7 +19,7 @@ ActiveMesh mesh; extern std::string path; extern int ID; -bool LoadNewMesh(const char* path,const int ID,const int fileNo); +bool LoadNewMesh(const char* path,const int ID,const int fileNo,const bool keepTipTrajectories=false); int main(int argc,char **argv) { @@ -99,12 +99,15 @@ int main(int argc,char **argv) std::cout << "triangles #: " << mesh.ID.size()/3 << "\n"; std::cout << "normals #: " << mesh.norm.size() << "\n"; - std::cout << "filopodia #: " << mesh.Ftree.size() << "\n"; + //std::cout << "filopodia #: " << mesh.Ftree.size() << "\n"; for (size_t f=0; f < mesh.Ftree.size(); ++f) { - std::cout << f << ": vertices #: " << mesh.Ftree[f].Pos.size() << "\n"; - std::cout << f << ": triangles #: " << mesh.Ftree[f].ID.size()/3 << "\n"; - std::cout << f << ": normals #: " << mesh.Ftree[f].norm.size() << "\n"; + if (mesh.Ftree[f].Pos.size() > 0) + { + std::cout << f << ": vertices #: " << mesh.Ftree[f].Pos.size() << "\n"; + std::cout << f << ": triangles #: " << mesh.Ftree[f].ID.size()/3 << "\n"; + std::cout << f << ": normals #: " << mesh.Ftree[f].norm.size() << "\n"; + } } } @@ -169,7 +172,7 @@ void ParamsSetup(void) } -bool LoadNewMesh(const char* path,const int ID,const int fileNo) +bool LoadNewMesh(const char* path,const int ID,const int fileNo,const bool keepTipTrajectories) { char fn[1024]; @@ -195,10 +198,11 @@ bool LoadNewMesh(const char* path,const int ID,const int fileNo) { ++filoNo; sprintf(fn,"%s/ID%d/ID%d_t%03d_fTree%02d.vtk",path,ID,ID,fileNo,filoNo); - std::cout << "reading filopodium: " << fn << "\n"; retval=mesh.ImportVTK_Ftree(fn,999999); - } while (retval == 0); + if (retval != 1) std::cout << "reading filopodium: " << fn << "\n"; + } while (retval < 2 && filoNo < 100); + //NB: retval == 0 when read successfully; == 1 when file open error //report errors except for "cannot open file" if (retval > 1) @@ -210,7 +214,10 @@ bool LoadNewMesh(const char* path,const int ID,const int fileNo) //remove last filopodium mesh (which is usually empty...) mesh.DiscardLastEmptyFilopodiumObject(); - std::cout << "loaded mesh #" << fileNo << " (with " << filoNo-1 << " filopodia)\n"; + //to get rid of unused parameter warning... + retval+=(keepTipTrajectories)? 1 : 0; + + std::cout << "loaded mesh #" << fileNo << "\n"; return(true); }