/* Copyright (C) 2012 University of Oxford */ /* Part of FSL - FMRIB's Software Library http://www.fmrib.ox.ac.uk/fsl fsl@fmrib.ox.ac.uk Developed at FMRIB (Oxford Centre for Functional Magnetic Resonance Imaging of the Brain), Department of Clinical Neurology, Oxford University, Oxford, UK LICENCE FMRIB Software Library, Release 5.0 (c) 2012, The University of Oxford (the "Software") The Software remains the property of the University of Oxford ("the University"). The Software is distributed "AS IS" under this Licence solely for non-commercial use in the hope that it will be useful, but in order that the University as a charitable foundation protects its assets for the benefit of its educational and research purposes, the University makes clear that no condition is made or to be implied, nor is any warranty given or to be implied, as to the accuracy of the Software, or that it will be suitable for any particular purpose or for use under any specific conditions. Furthermore, the University disclaims all responsibility for the use which is made of the Software. It further disclaims any liability for the outcomes arising from using the Software. The Licensee agrees to indemnify the University and hold the University harmless from and against any and all claims, damages and liabilities asserted by third parties (including claims for negligence) which arise directly or indirectly from the use of the Software or the sale of any products based on the Software. No part of the Software may be reproduced, modified, transmitted or transferred in any form or by any means, electronic or mechanical, without the express permission of the University. The permission of the University is not required if the said reproduction, modification, transmission or transference is done without financial return, the conditions of this Licence are imposed upon the receiver of the product, and all original and amended source code is included in any transmitted product. You may be held legally responsible for any copyright infringement that is caused or encouraged by your failure to abide by these terms and conditions. You are not permitted under this Licence to use this Software commercially. Use for which any financial return is received shall be defined as commercial use, and includes (1) integration of all or part of the source code or the Software into a product for sale or license by or on behalf of Licensee to third parties or (2) use of the Software or any derivative of it for research with the final aim of developing software products for sale or license to a third party or (3) use of the Software or any derivative of it for research with the final aim of developing non-software products for sale or license to a third party, or (4) use of the Software to provide any service to an external organisation for which payment is received. If you are interested in using the Software commercially, please contact Isis Innovation Limited ("Isis"), the technology transfer company of the University, to negotiate a licence. Contact details are: innovation@isis.ox.ac.uk quoting reference DE/9564. */ #include "streamlines.h" #include "warpfns/fnirt_file_reader.h" #include "warpfns/warpfns.h" namespace TRACT{ void read_ascii_files(const string& filename,vector& content){ ifstream fs(filename.c_str()); string tmp; if(fs){ fs>>tmp; do{ content.push_back(tmp); fs>>tmp; }while(!fs.eof()); } else{ cerr<<"TRACT::read_ascii_files: "< tmp(M.Nrows(),M.Ncols(),1); for(int i=1;i<=M.Nrows();i++) for(int j=1;j<=M.Ncols();j++) tmp(i-1,j-1,0)=M(i,j); save_volume(tmp,filename); } ColumnVector mean_sph_pol(ColumnVector& A, ColumnVector& B){ // A and B contain th, ph f. float th,ph; ColumnVector rA(3), rB(3); rA << (sin(A(1))*cos(A(2))) << (sin(A(1))*sin(A(2))) << (cos(A(1))); rB << (sin(B(1))*cos(B(2))) << (sin(B(1))*sin(B(2))) << (cos(B(1))); if(sum(SP(rA,rB)).AsScalar()>0) cart2sph((rA+rB)/2,th,ph); else cart2sph((rA-rB)/2,th,ph); A(1)=th; A(2)=ph; return A; } void imgradient(const volume& im,volume4D& grad){ grad.reinitialize(im.xsize(),im.ysize(),im.zsize(),3); copybasicproperties(im,grad[0]); int fx,fy,fz,bx,by,bz; float dx,dy,dz; for (int z=0; z& x,vector& y){ // sort vector< pair > p; for(unsigned int i=0;i pp; pp.first=x[i]; pp.second=i; p.push_back(pp); } sort(p.begin(),p.end()); vector ycp(y.begin(),y.end()); for(unsigned int i=0;i xx;vector yy; for(unsigned int i=0;i0){ if( x[i]==x[i-1] )continue; } xx.push_back(x[i]); yy.push_back(y[i]); } x=xx; y=yy; } void make_unique(vector< pair >&x){ sort(x.begin(),x.end()); vector< pair > xx; for(unsigned int i=0;i0){ if( x[i].first==x[i-1].first )continue; } xx.push_back(x[i]); } x=xx; } Streamliner::Streamliner(const CSV& seeds):opts(probtrackxOptions::getInstance()), logger(LogSingleton::getInstance()), vols(opts.usef.value()), m_seeds(seeds) { // the tracking mask - no tracking outside of this read_volume(m_mask,opts.maskfile.value()); // particle m_part.initialise(0,0,0,0,0,0,opts.steplength.value(), m_mask.xdim(),m_mask.ydim(),m_mask.zdim(), false); // no-integrity if(opts.skipmask.value()!="") read_volume(m_skipmask,opts.skipmask.value()); // loop checking box m_lcrat=5; // hard-coded! box is five times smaller than brain mask if(opts.loopcheck.value()){ m_loopcheck.reinitialize(int(ceil(m_mask.xsize()/m_lcrat)+1), int(ceil(m_mask.ysize()/m_lcrat)+1), int(ceil(m_mask.zsize()/m_lcrat)+1),3); m_loopcheck=0; } // exclusion mask // now in CSV format if(opts.rubbishfile.value()!=""){ load_rubbish(opts.rubbishfile.value()); } // stopping mask // now in CSV format if(opts.stopfile.value()!=""){ load_stop(opts.stopfile.value()); } // waymasks in CSV format if(opts.waypoints.set()){ load_waymasks(opts.waypoints.value()); m_waycond=opts.waycond.value(); } // choose preferred fibre within this mask (prior knowledge) if(opts.prefdirfile.value()!=""){ read_volume4D(m_prefdir,opts.prefdirfile.value()); } // Allow for either matrix transform (12dof affine) or nonlinear (warpfield) m_Seeds_to_DTI = IdentityMatrix(4); m_DTI_to_Seeds = IdentityMatrix(4); m_rotdir = IdentityMatrix(3); m_IsNonlinXfm = false; if(opts.seeds_to_dti.value()!=""){ if(!fsl_imageexists(opts.seeds_to_dti.value())){//presumably ascii file provided m_Seeds_to_DTI = read_ascii_matrix(opts.seeds_to_dti.value()); m_DTI_to_Seeds = m_Seeds_to_DTI.i(); m_rotdir = m_Seeds_to_DTI.SubMatrix(1,3,1,3); } else{ m_IsNonlinXfm = true; FnirtFileReader ffr(opts.seeds_to_dti.value()); m_Seeds_to_DTI_warp = ffr.FieldAsNewimageVolume4D(true); if(opts.dti_to_seeds.value()==""){ cerr << "TRACT::Streamliner:: DTI -> Seeds transform needed" << endl; exit(1); } FnirtFileReader iffr(opts.dti_to_seeds.value()); m_DTI_to_Seeds_warp = iffr.FieldAsNewimageVolume4D(true); // now calculate the jacobian of this transformation (useful for rotating vectors) imgradient(m_Seeds_to_DTI_warp[0],m_jacx); imgradient(m_Seeds_to_DTI_warp[1],m_jacy); imgradient(m_Seeds_to_DTI_warp[2],m_jacz); } } vols.initialise(opts.basename.value(),m_mask); m_path.reserve(opts.nsteps.value()); m_x_s_init=0; m_y_s_init=0; m_z_s_init=0; m_inmask3.reserve(opts.nsteps.value()); m_inlrmask3.reserve(opts.nsteps.value()); } void Streamliner::rotdir(const ColumnVector& dir,ColumnVector& rotdir, const float& x,const float& y,const float& z){ if(!m_IsNonlinXfm){ rotdir = m_rotdir*dir; if(rotdir.MaximumAbsoluteValue()>0) rotdir = rotdir/std::sqrt(rotdir.SumSquare()); } else{ ColumnVector xyz_dti(3),xyz_seeds(3); xyz_seeds << x << y << z; xyz_dti = NewimageCoord2NewimageCoord(m_DTI_to_Seeds_warp, false,m_seeds.get_refvol(),m_mask,xyz_seeds); Matrix F(3,3),Jw(3,3); int x=(int)round((float)xyz_dti(1)); int y=(int)round((float)xyz_dti(2)); int z=(int)round((float)xyz_dti(3)); Jw << m_jacx(x,y,z,0) << m_jacx(x,y,z,1) << m_jacx(x,y,z,2) << m_jacy(x,y,z,0) << m_jacy(x,y,z,1) << m_jacy(x,y,z,2) << m_jacz(x,y,z,0) << m_jacz(x,y,z,1) << m_jacz(x,y,z,2); F = (IdentityMatrix(3) + Jw).i(); rotdir = F*dir; if(rotdir.MaximumAbsoluteValue()>0) rotdir = rotdir/std::sqrt(rotdir.SumSquare()); } } int Streamliner::streamline(const float& x_init,const float& y_init,const float& z_init, const ColumnVector& dim_seeds,const int& fibst,const int& seed_ind){ //Tracer_Plus tr("Streamliner::streamline"); //fibst tells tractvolsx which fibre to start with if there are more than one.. //x_init etc. are in seed space... vols.reset(fibst); m_x_s_init=x_init; // seed x position in voxels m_y_s_init=y_init; // and y m_z_s_init=z_init; // and z ColumnVector xyz_seeds(3); xyz_seeds< waycrossed; vector crossedlocs3; int cnt=-1; // loopcheck stuff float oldrx,oldry,oldrz; int lcx,lcy,lcz; bool forcedir=false; //NB - this only goes in one direction!! if(opts.onewaycondition.value()){ for(unsigned int i=0; i1) logger<=0){ if(!m_IsNonlinXfm) xyz_seeds = vox_to_vox(xyz_dti,vols.dimensions(),dim_seeds,m_DTI_to_Seeds); else{ xyz_seeds = NewimageCoord2NewimageCoord(m_Seeds_to_DTI_warp,false,m_mask,m_seeds.get_refvol(),xyz_dti); } } x_s =(int)round((float)xyz_seeds(1)); y_s =(int)round((float)xyz_seeds(2)); z_s =(int)round((float)xyz_seeds(3)); // how prefdir works: // if a vector field is given (tested using 4th dim==3) then set prefdir to that orientation // eventually will be flipped to match the current direction of travel // if dim4<3, then : // - use dim1 scalar as fibre sampling method (i.e. randfib 1 2 3 ) // - use dim2 scalar (when given) as which fibre to follow blindly, i.e. without flipping pref_x=0;pref_y=0;pref_z=0; int sample_fib = 0; if(opts.prefdirfile.value()!=""){ if(m_prefdir.tsize()==3){ pref_x = m_prefdir((int)x,(int)y,(int)z,0); pref_y = m_prefdir((int)x,(int)y,(int)z,1); pref_z = m_prefdir((int)x,(int)y,(int)z,2); } else{ if(m_prefdir(x_s,y_s,z_s,0)!=0) sample_fib = (int)m_prefdir((int)x,(int)y,(int)z,0); if(sample_fib>3)sample_fib=3; } } // // attractor mask // if(opts.pullmask.value()!=""){ // ColumnVector pulldir(3);float mindist; // if(m_pullmask.is_near_surface(xyz_seeds,opts.pulldist.value(),pulldir,mindist)){ // m_prefx = pulldir(1); // m_prefy = pulldir(2); // m_prefz = pulldir(3); // } // } // augment the path m_path.push_back(xyz_seeds);cnt++; if(cnt>0) pathlength += opts.steplength.value(); // // // if first step and onewayonly // // if(opts.onewayonly.value() && m_path.size()==2){ // // Vec step(m_path[1](1)-m_path[0](1), // // m_path[1](2)-m_path[0](2), // // m_path[1](3)-m_path[0](3)); // // if(m_seeds.coord_sign(seed_ind,m_path[0]+0.001*(m_path[1]-m_path[0]))<0){ // // rubbish_passed=1; // // break; // // } // // } // only test exclusion after at least one step if(opts.rubbishfile.value()!="" && cnt>0){ if(m_rubbish.has_crossed(m_path[cnt-1],m_path[cnt])){ rubbish_passed=1; break; } } // update every passed_flag if(m_way_passed_flags.size()>0){ if(cnt>0){ waycrossed.clear(); m_waymasks.has_crossed_roi(m_path[cnt-1],m_path[cnt],waycrossed); for(unsigned int wm=0;wm0){ waycrossed.clear(); m_netmasks.has_crossed_roi(m_path[cnt-1],m_path[cnt],waycrossed); for(unsigned int wm=0;wm0){ waycrossed.clear();crossedlocs3.clear(); if(m_mask3.has_crossed_roi(m_path[cnt-1],m_path[cnt],waycrossed,crossedlocs3)){ fill_inmask3(crossedlocs3,pathlength); } if(opts.lrmask3.value()!=""){ waycrossed.clear();crossedlocs3.clear(); if(m_lrmask3.has_crossed_roi(m_path[cnt-1],m_path[cnt],waycrossed,crossedlocs3)){ fill_inlrmask3(crossedlocs3,pathlength); } } } // only test stopping after at least one step if(opts.stopfile.value()!="" && m_path.size()>1){ if(m_path.size()==2 && opts.forcefirststep.value()){ // do nothing } else if(m_stop.has_crossed(m_path[cnt-1],m_path[cnt])){ break; } } // ////////////////////////////// // sample a new fibre orientation int sampled_fib,newx,newy,newz; if(opts.skipmask.value() == ""){ //Tracer_Plus tr("sample"); th_ph_f = vols.sample(m_part.x(),m_part.y(),m_part.z(), // sample at this location m_part.rx(),m_part.ry(),m_part.rz(), // choose closest sample to this pref_x,pref_y,pref_z, // unless we have this prefered direction sample_fib, // controls probabilities of sampling a given fibre sampled_fib, // which fibre has been sampled newx,newy,newz); // which voxel has been considered } else{ if(m_skipmask(x_s,y_s,z_s)==0)//only sample outside skipmask th_ph_f=vols.sample(m_part.x(),m_part.y(),m_part.z(), m_part.rx(),m_part.ry(),m_part.rz(), pref_x,pref_y,pref_z, sample_fib, sampled_fib, newx,newy,newz); } // // depending on which fibre has been sampled, decide whether to forcedir // forcedir=false; // if(opts.prefdirfile.value()!=""){ // if(m_prefdir.tsize()==2){ // if(m_prefdir(newx,newy,newz,1)==sampled_fib) // forcedir=true; // } // } // jump tmp2=(float)rand()/(float)RAND_MAX; if(th_ph_f(3)>tmp2){ //volume fraction criterion if(!m_part.check_dir(th_ph_f(1),th_ph_f(2),opts.c_thr.value(),forcedir)){// curvature threshold //cout<<"curv break"<0)numpassed++; } if(numpassed==0)rejflag=1; else if(numpassed (m_numseeds,m_numseeds); m_Conrow1 = 1; vector coords = m_stline.get_seeds().get_locs_coords(); vector roicind = m_stline.get_seeds().get_locs_coord_index(); vector roiind = m_stline.get_seeds().get_locs_roi_index(); Matrix CoordMat1(m_numseeds,5); for (unsigned int i=0;i (m_numseeds,numnz); if( !opts.simple.value()){ vector coords = m_stline.get_seeds().get_locs_coords(); vector roicind = m_stline.get_seeds().get_locs_coord_index(); vector roiind = m_stline.get_seeds().get_locs_roi_index(); Matrix CoordMat2(m_numseeds,5); for (unsigned int i=0;i (nmask3,nlrmask3); //OUT(m_ConMat3->Nrows()); //OUT(m_ConMat3->Ncols()); //exit(1); // save lookup tables... CSV mask3(m_stline.get_mask3()); vector coords = mask3.get_locs_coords(); vector roicind = mask3.get_locs_coord_index(); vector roiind = mask3.get_locs_roi_index(); Matrix mat(mask3.nLocs(),5); for (unsigned int i=0;i lrcoords = lrmask3.get_locs_coords(); vector lrroicind = lrmask3.get_locs_coord_index(); vector lrroiind = lrmask3.get_locs_roi_index(); Matrix lrmat(lrmask3.nLocs(),5); for (unsigned int i=0;i crossedrois,crossedlocs; int nlocs=0; for(unsigned int i=0;i0 && (m_path[i]-m_path[0]).MaximumAbsoluteValue()==0){ pathlength=0; } if(m_beenhere(x_s,y_s,z_s)==0){ if(!opts.pathdist.value()) m_prob(x_s,y_s,z_s)+=1; else m_prob(x_s,y_s,z_s)+=pathlength; m_beenhere(x_s,y_s,z_s)=1; if(opts.opathdir.value() && i>0){ ColumnVector v(3); v=m_path[i]-m_path[i-1]; v/=std::sqrt(v.SumSquare()); m_localdir(x_s,y_s,z_s,0)+=v(1); m_localdir(x_s,y_s,z_s,1)+=v(2); m_localdir(x_s,y_s,z_s,2)+=v(3); } } // Fill alternative mask // This mask's values are: // 0: location not to be considered // 1: location has not been visited // 2: location has been visited if(opts.pathfile.set()){ if(pathlength>0){ crossedrois.clear();crossedlocs.clear(); if(m_beenhere_alt.has_crossed_roi(m_path[i-1],m_path[i],crossedrois,crossedlocs)){ nlocs+=crossedlocs.size(); for(unsigned int i=0;i crossedlocs,crossedrois; bool hascrossed=false; for(unsigned int i=0;i0 && (m_path[i]-m_path[0]).MaximumAbsoluteValue()==0) continue; // alternative roi if(opts.pathfile.set()){ if(i>0){ if(m_beenhere_alt.has_crossed_roi(m_path[i-1],m_path[i],crossedrois,crossedlocs)) hascrossed=true; } } } if(opts.pathfile.set() && hascrossed){ //cout<<"reset"<1) m_beenhere_alt.set_value(crossedlocs[i],1); } } } void Counter::add_path(){ m_save_paths.push_back(m_path); } void Counter::save_paths(){ string filename=logger.appendDir("saved_paths.txt"); ofstream of(filename.c_str()); if (of.is_open()){ for(unsigned int i=0;i crossed; float pathlength=0; int cnt=0; for(unsigned int i=1;i crossedseeds,crossedlocs; vector allcrossed;vector allvals; for(unsigned int i=1;i vals(crossedlocs.size(),val); allvals.insert(allvals.end(),vals.begin(),vals.end()); } val = opts.pathdist.value()?pathlength:1; pathlength+=opts.steplength.value(); } // fill matrix1 make_unique(allcrossed,allvals); for(unsigned int i=0;iAddTo(m_Conrow1,allcrossed[i]+1,allvals[i]); } } void Counter::update_matrix2_row(){ //run this one every streamline - not every voxel.. float d=opts.steplength.value(); int x_lr,y_lr,z_lr,Concol2; ColumnVector xyz_lr(3); for(unsigned int i=0;i0 && (m_path[i]-m_path[0]).MaximumAbsoluteValue()==0) d=opts.steplength.value(); xyz_lr=vox_to_vox(m_path[i],m_seedsdim,m_lrdim,m_I); x_lr=(int)round((float)xyz_lr(1)); y_lr=(int)round((float)xyz_lr(2)); z_lr=(int)round((float)xyz_lr(3)); Concol2=m_lookup2(x_lr,y_lr,z_lr); if(Concol2>0){ if(m_beenhere2(x_lr,y_lr,z_lr)==0){ if(!opts.pathdist.value()) m_ConMat2->AddTo(m_curloc+1,Concol2,1); else m_ConMat2->AddTo(m_curloc+1,Concol2,d); m_beenhere2(x_lr,y_lr,z_lr)=1; d+=opts.steplength.value(); } } } } void Counter::update_matrix3(){ vector< pair >& inmask3 = m_stline.get_inmask3(); vector< pair >& inlrmask3 = m_stline.get_inlrmask3(); bool uselr = (opts.lrmask3.value()!=""); if(!uselr){ if(inmask3.size()<2)return; } else{ if(inmask3.size()<1 || inlrmask3.size()<1)return; } // remove duplicates make_unique(inmask3); if(!uselr){// where we update NxN matrix for(unsigned int i=0;iAddTo(inmask3[i].first+1,inmask3[j].first+1,1); else{ float val = fabs(inmask3[i].second-inmask3[j].second); m_ConMat3->AddTo(inmask3[i].first+1,inmask3[j].first+1,val); } } } } else{ // where we update Nxn matrix make_unique(inlrmask3); for(unsigned int i=0;iAddTo(inmask3[i].first+1,inlrmask3[j].first+1,1); else{ float val = fabs(inmask3[i].second-inlrmask3[j].second); m_ConMat3->AddTo(inmask3[i].first+1,inlrmask3[j].first+1,val); } } } } } void Counter::reset_beenhere3(){ m_stline.clear_inmask3(); m_stline.clear_inlrmask3(); } void Counter::reset_beenhere2(){ ColumnVector xyz_lr(3); for(unsigned int i=0;i& keeptotal){ // save total number of particles that made it through the streamlining ColumnVector keeptotvec(keeptotal.size()); for (int i=1;i<=(int)keeptotal.size();i++) keeptotvec(i)=keeptotal[i-1]; write_ascii_matrix(keeptotvec,logger.appendDir("waytotal")); } void Counter::save(){ if(opts.simpleout.value() && !opts.simple.value()){ save_pathdist(); } if(opts.save_paths.value()) save_paths(); if(opts.s2tout.value()){ save_seedcounts(); } if(opts.matrix1out.value()){ save_matrix1(); } if(opts.matrix2out.value()){ save_matrix2(); } if(opts.matrix3out.value()){ save_matrix3(); } } void Counter::save_pathdist(){ m_prob.setDisplayMaximumMinimum(m_prob.max(),m_prob.min()); save_volume(m_prob,logger.appendDir(opts.outfile.value())); if(opts.pathfile.set()){ m_prob_alt.save_rois(logger.appendDir(opts.outfile.value())+"_alt"); //m_beenhere_alt.save_rois(logger.appendDir(opts.outfile.value())+"_beenhere"); } if(opts.opathdir.value()){ for(int z=0;z=0){ lastpos=pos; pos=tmpname.find("/",pos); // replace / with _ tmpname[pos]='_'; } //only take things after the last pos tmpname=tmpname.substr(lastpos+1,tmpname.length()-lastpos-1); if(m_s2t_count.nRois()>1){ for(int i=0;i& coordvol, const Matrix& old2new_mat) { for (int n=0; n<=coordvol.maxx(); n++) { ColumnVector v(4); v << coordvol(n,0,0) << coordvol(n,1,0) << coordvol(n,2,0) << 1.0; v = old2new_mat * v; coordvol(n,0,0) = MISCMATHS::round(v(1)); coordvol(n,1,0) = MISCMATHS::round(v(2)); coordvol(n,2,0) = MISCMATHS::round(v(3)); } } void applycoordchange(Matrix& coordvol, const Matrix& old2new_mat) { for (int n=1; n<=coordvol.Nrows(); n++) { ColumnVector v(4); v << coordvol(n,1) << coordvol(n,2) << coordvol(n,3) << 1.0; v = old2new_mat * v; coordvol(n,1) = v(1); coordvol(n,2) = v(2); coordvol(n,3) = v(3); } } void Counter::save_matrix1(){ m_ConMat1->Print(logger.appendDir("fdt_matrix1.dot")); } void Counter::save_matrix2(){ m_ConMat2->Print(logger.appendDir("fdt_matrix2.dot")); } void Counter::save_matrix3(){ m_ConMat3->Print(logger.appendDir("fdt_matrix3.dot")); } int Seedmanager::run(const float& x,const float& y,const float& z, bool onewayonly, int fibst,float sampvox){ int seed_ind=-1; // run without forcing the tracking direction return run(x,y,z,onewayonly,fibst,sampvox,seed_ind); } // this function returns the total number of pathways that survived a streamlining int Seedmanager::run(const float& x,const float& y,const float& z, bool onewayonly, int fibst,float sampvox,const int& seed_ind){ //Tracer_Plus tr("Seedmanager::run"); //onewayonly for mesh things.. if(opts.fibst.set()){ fibst=opts.fibst.value()-1; } else{ if(fibst == -1){ fibst=0; } //TB moved randfib option inside tractvols.h 28/10/2009 // This means that we have access to fsamples when figuring out fibst // so we can choose to seed in proportion to f in that voxel. } int nlines=0; for(int p=0;p2){ //This bit of code just does random sampling from all fibre populations - even those whose f value is less than f-thresh. //3 other possibilities - randfib==0 -> use fibst (default first fibre but can be set) // randfib==1 - random sampling of fibres bigger than fthresh // randfib==2 random sampling of fibres bigger than fthresh in proporthion to their f-values. float tmp=rand()/float(RAND_MAX) * float(m_counter.get_stline().nfibres()-1); fibst = (int)round(tmp); } // random sampling within a seed voxel float newx=x,newy=y,newz=z; if(sampvox>0){ bool rej=true;float dx,dy,dz;float r2=sampvox*sampvox; while(rej){ dx=2.0*sampvox*((float)rand()/float(RAND_MAX)-.5); dy=2.0*sampvox*((float)rand()/float(RAND_MAX)-.5); dz=2.0*sampvox*((float)rand()/float(RAND_MAX)-.5); if( dx*dx+dy*dy+dz*dz <= r2 ) rej=false; } newx+=dx/m_seeddims(1); newy+=dy/m_seeddims(2); newz+=dz/m_seeddims(3); } if(opts.verbose.value()>1) logger.setLogFile("particle"+num2str(p)); m_counter.get_stline().reset(); //This now includes a vols.reset() in order to get fibst right. bool forwardflag=false,backwardflag=false; int rejflag1=1,rejflag2=1; // 0:accept, 1:reject, 2:wait m_counter.clear_path(); // track in one direction if(!onewayonly || opts.matrix3out.value()){//always go both ways in matrix3 mode rejflag1 = m_counter.get_stline().streamline(newx,newy,newz,m_seeddims,fibst,seed_ind); if(rejflag1==0 || rejflag1==2){ forwardflag=true; m_counter.append_path(); if(opts.save_paths.value()) m_counter.add_path(); } m_counter.get_stline().reverse(); } // track in the other direction // if rotdir!=0 then this tracks again in the same direction (doubles the number of samples...) rejflag2=m_counter.get_stline().streamline(newx,newy,newz,m_seeddims,fibst,seed_ind); if(rejflag2==0){ backwardflag=true; } if(rejflag2>0){ backwardflag=false; if(rejflag1>0) forwardflag=false; } if(!forwardflag) m_counter.clear_path(); if(backwardflag){ m_counter.append_path(); if(opts.save_paths.value()) m_counter.add_path(); } if(forwardflag || backwardflag){ nlines++; m_counter.count_streamline(); if(opts.matrix3out.value()||opts.matrix1out.value()){ float pathlength; if( !forwardflag || !backwardflag) pathlength = m_counter.calc_pathlength(0); else // if the paths are appended, one step has zero length pathlength = m_counter.calc_pathlength(1); if(opts.matrix3out.value() && pathlength>=opts.distthresh3.value()) m_counter.update_matrix3(); if(opts.matrix1out.value() && pathlength>=opts.distthresh1.value()) m_counter.update_matrix1(); } } m_counter.clear_streamline(); } m_counter.count_seed(); return nlines; } }