Commit 52cb8dfd2dc3f38bd35a6860afad2f86f4ec5f53

Authored by pranathivemuri
1 parent 1c3c8f1a

added function to resample a fiber in the network, adding resampled edges to the network

Showing 1 changed file with 132 additions and 88 deletions   Show diff stats
stim/visualization/network.h
@@ -14,7 +14,6 @@ @@ -14,7 +14,6 @@
14 #include <ANN/ANN.h> 14 #include <ANN/ANN.h>
15 #include <boost/tuple/tuple.hpp> 15 #include <boost/tuple/tuple.hpp>
16 16
17 -#define multfactor 2.51  
18 17
19 namespace stim{ 18 namespace stim{
20 /** This is the a class that interfaces with gl_spider in order to store the currently 19 /** This is the a class that interfaces with gl_spider in order to store the currently
@@ -171,10 +170,13 @@ class network{ @@ -171,10 +170,13 @@ class network{
171 edges_to_str() 170 edges_to_str()
172 { 171 {
173 std::ostringstream ss; 172 std::ostringstream ss;
  173 + std::cout<<"here"<<std::endl;
174 // ss << "["; 174 // ss << "[";
175 for(int i = 0; i < edges.size()-1; i++) 175 for(int i = 0; i < edges.size()-1; i++)
176 { 176 {
  177 + std::cout<<"here"<<i<<std::endl;
177 ss << edges[i] << ";"; 178 ss << edges[i] << ";";
  179 + std::cout<<edges.size()-1<<std::endl;
178 } 180 }
179 ss << edges[edges.size()-1]; 181 ss << edges[edges.size()-1];
180 // ss << "]"; 182 // ss << "]";
@@ -187,6 +189,8 @@ class network{ @@ -187,6 +189,8 @@ class network{
187 189
188 std::vector<edge*> E; //list of pointers to edges. 190 std::vector<edge*> E; //list of pointers to edges.
189 std::vector<node> V; //list of nodes. 191 std::vector<node> V; //list of nodes.
  192 + std::vector< stim::vec<T> > allVerticesList; // all nodes before sampling
  193 + std::vector<stim::vec<T> > allVerticesAfterSampling ; //all vertices after sampling
190 194
191 ///Returns the number of edges in the network. 195 ///Returns the number of edges in the network.
192 unsigned int 196 unsigned int
@@ -201,7 +205,11 @@ class network{ @@ -201,7 +205,11 @@ class network{
201 { 205 {
202 return V.size(); 206 return V.size();
203 } 207 }
204 - 208 + unsigned int
  209 + sizeAfterSamplingV()
  210 + {
  211 + return allVerticesAfterSampling.size();
  212 + }
205 /* //adds an edge from two std::vectors with positions and radii. 213 /* //adds an edge from two std::vectors with positions and radii.
206 void 214 void
207 addEdge(std::vector< stim::vec<T> > pos, std::vector<stim::vec<T> > radii, int endId) 215 addEdge(std::vector< stim::vec<T> > pos, std::vector<stim::vec<T> > radii, int endId)
@@ -500,7 +508,7 @@ class network{ @@ -500,7 +508,7 @@ class network{
500 totalEdges() 508 totalEdges()
501 { 509 {
502 int totalEdgeVertices=0;int N=0; 510 int totalEdgeVertices=0;int N=0;
503 - for (int i=0; i < sizeE(); i ++) 511 + for (unsigned int i=0; i < sizeE(); i ++)
504 {// FOR N points on the fiber N-1 edges are possible 512 {// FOR N points on the fiber N-1 edges are possible
505 N = E[i]->n_pts(); 513 N = E[i]->n_pts();
506 totalEdgeVertices = totalEdgeVertices + N- 1; 514 totalEdgeVertices = totalEdgeVertices + N- 1;
@@ -512,46 +520,13 @@ class network{ @@ -512,46 +520,13 @@ class network{
512 lengthOfNetwork() 520 lengthOfNetwork()
513 { 521 {
514 float networkLength=0;float N=0; 522 float networkLength=0;float N=0;
515 - for (int i=0; i < sizeE(); i ++) 523 + for (unsigned int i=0; i < sizeE(); i ++)
516 { 524 {
517 N = E[i]->length(); 525 N = E[i]->length();
518 networkLength = networkLength + N; 526 networkLength = networkLength + N;
519 } 527 }
520 return networkLength; 528 return networkLength;
521 } 529 }
522 - /// get index of a node on a fiber  
523 - // by matching the node on fiber to already set vertices (both strings)  
524 - // used in obj file conversion  
525 - int  
526 - getIndexes(std::string* input, std::string searched, int sizeV)  
527 - {  
528 - int result = 0;  
529 - for (int i = 0; i < sizeV; i++)  
530 - {  
531 - if (input[i] == searched)  
532 - {  
533 - result = i + 1;  
534 - }  
535 - }  
536 - return result;  
537 - }  
538 - // strObj returns a string of fiber indices corresponding to vectors of positions in the fiber including intermediate nodes  
539 - std::string  
540 - strObj(std::string* strArray, int sizeV)  
541 - {  
542 - std::stringstream ss;  
543 - std::stringstream oss;  
544 - for(unsigned int i = 0; i < N; i++)  
545 - {  
546 - ss.str(std::string());  
547 - for(unsigned int d = 0; d < 3; d++)  
548 - {  
549 - ss<<c[i][d];  
550 - }  
551 - oss<<getIndexes(strArray, ss.str(), sizeV)<<" ";  
552 - }  
553 - return oss.str();  
554 - }  
555 ///@param i: index of the required fiber. 530 ///@param i: index of the required fiber.
556 ///Returns an std::vector with the centerline of the ith fiber in the edgelist. 531 ///Returns an std::vector with the centerline of the ith fiber in the edgelist.
557 std::vector< stim::vec<T> > 532 std::vector< stim::vec<T> >
@@ -584,6 +559,7 @@ class network{ @@ -584,6 +559,7 @@ class network{
584 objToNetwork(stim::obj<T> objInput) 559 objToNetwork(stim::obj<T> objInput)
585 { 560 {
586 stim::network<T> nwc; 561 stim::network<T> nwc;
  562 + //network network2;
587 // function to convert an obj file loaded using stim/visualization/obj.h 563 // function to convert an obj file loaded using stim/visualization/obj.h
588 // to a 3D network class using network.h methods. 564 // to a 3D network class using network.h methods.
589 std::vector< stim::vec<T> > fiberPositions; //initialize positions on the fiber to be added to network 565 std::vector< stim::vec<T> > fiberPositions; //initialize positions on the fiber to be added to network
@@ -595,7 +571,8 @@ class network{ @@ -595,7 +571,8 @@ class network{
595 // using addNode function for adding nodes 571 // using addNode function for adding nodes
596 // and the line as an edge(belongs to fiber class) using addEdge function 572 // and the line as an edge(belongs to fiber class) using addEdge function
597 std::vector<unsigned> vertexIndices(objInput.numV()); 573 std::vector<unsigned> vertexIndices(objInput.numV());
598 - std::vector< stim::vec<T> > allVerticesList = objInput.getAllV(vertexIndices); 574 + std::vector< stim::vec<T> > vertices = objInput.getAllV(vertexIndices);
  575 + nwc.addVertices(vertices);
599 for (unsigned i =1; i< objInput.numL() + 1; i++) 576 for (unsigned i =1; i< objInput.numL() + 1; i++)
600 { 577 {
601 // edges/fibers could be added to the network class 578 // edges/fibers could be added to the network class
@@ -630,28 +607,33 @@ class network{ @@ -630,28 +607,33 @@ class network{
630 { 607 {
631 fiberPositions1 = fiberPositions; 608 fiberPositions1 = fiberPositions;
632 } 609 }
633 - std::vector<T> radii(numPointsOnFiber); // allocating radii to zero  
634 // then add edge 610 // then add edge
635 - // edge* a = new edge(fiberPositions1,radii);  
636 - //E.push_back(a);  
637 - nwc.addEdge(fiberPositions1, radii); 611 + //edge* a = new edge(fiberPositions1,radii);
  612 + //std::cout<<"here"<<std::endl;
  613 + //E.push_back(a);
  614 + std::vector<stim::vec<T> > newPointList;
  615 + newPointList = Resample(fiberPositions1);
  616 + int numPointsOnnewFiber = newPointList.size();
  617 + nwc.addVerticesAfterSamplimg(newPointList);
  618 + std::vector<T> radii(numPointsOnnewFiber); // allocating radii to zero
  619 + nwc.addEdge(newPointList, radii);
638 // add nodes 620 // add nodes
639 stim::vec<T> v0(3);stim::vec<T> vN(3); 621 stim::vec<T> v0(3);stim::vec<T> vN(3);
640 - int endId = numPointsOnFiber -1;  
641 - v0[0] = fiberPositions1[0][0];v0[1] = fiberPositions1[0][1];v0[2] = fiberPositions1[0][2];  
642 - vN[0] = fiberPositions1[endId][0];vN[1] = fiberPositions1[endId][1];vN[2] = fiberPositions1[endId][2]; 622 + int endId = numPointsOnnewFiber -1;
  623 + v0[0] = newPointList[0][0];v0[1] = newPointList[0][1];v0[2] = newPointList[0][2];
  624 + vN[0] = newPointList[endId][0];vN[1] = newPointList[endId][1];vN[2] = newPointList[endId][2];
643 // VISITED INDEXES OF the nodes are set to true 625 // VISITED INDEXES OF the nodes are set to true
644 - if(!validList[objInput.getIndex(allVerticesList, v0)]) 626 + if(!validList[objInput.getIndex(vertices, v0)])
645 { 627 {
646 //V.push_back(node(v0)); 628 //V.push_back(node(v0));
647 nwc.addNode(v0); 629 nwc.addNode(v0);
648 - validList[objInput.getIndex(allVerticesList, v0)] = true; 630 + validList[objInput.getIndex(vertices, v0)] = true;
649 } 631 }
650 - if(!validList[objInput.getIndex(allVerticesList, vN)]) 632 + if(!validList[objInput.getIndex(vertices, vN)])
651 { 633 {
652 //V.push_back(node(vN)); 634 //V.push_back(node(vN));
653 nwc.addNode(vN); 635 nwc.addNode(vN);
654 - validList[objInput.getIndex(allVerticesList, vN)] = true; 636 + validList[objInput.getIndex(vertices, vN)] = true;
655 } 637 }
656 } 638 }
657 return nwc; 639 return nwc;
@@ -672,6 +654,7 @@ class network{ @@ -672,6 +654,7 @@ class network{
672 kdTree2 = generateKdTreeFromNetwork(network2); 654 kdTree2 = generateKdTreeFromNetwork(network2);
673 std::cout<<"Test Network:network and kdtree generated"<<std::endl; 655 std::cout<<"Test Network:network and kdtree generated"<<std::endl;
674 return boost::make_tuple(kdTree1, kdTree2, network1, network2); 656 return boost::make_tuple(kdTree1, kdTree2, network1, network2);
  657 + std::cout<<"out of this loop"<<std::endl;
675 } 658 }
676 //distance between two points 659 //distance between two points
677 double dist(std::vector<T> p0, std::vector<T> p1) 660 double dist(std::vector<T> p0, std::vector<T> p1)
@@ -686,7 +669,7 @@ class network{ @@ -686,7 +669,7 @@ class network{
686 double sum(stim::vec<T> metricList) 669 double sum(stim::vec<T> metricList)
687 { 670 {
688 float sumMetricList = 0; 671 float sumMetricList = 0;
689 - for (int count=0; count<metricList.size(); count++) 672 + for (unsigned int count=0; count<metricList.size(); count++)
690 { sumMetricList += metricList[count];} 673 { sumMetricList += metricList[count];}
691 return sumMetricList; 674 return sumMetricList;
692 } 675 }
@@ -694,21 +677,22 @@ class network{ @@ -694,21 +677,22 @@ class network{
694 ANNkd_tree* 677 ANNkd_tree*
695 generateKdTreeFromNetwork(stim::network<T> network) //kd-tree stores all points in the fiber for fast searching 678 generateKdTreeFromNetwork(stim::network<T> network) //kd-tree stores all points in the fiber for fast searching
696 { 679 {
  680 + std::cout<<"kd trees generated"<<std::endl;
697 ANNkd_tree* kdt; 681 ANNkd_tree* kdt;
698 double **c; //centerline (array of double pointers) 682 double **c; //centerline (array of double pointers)
699 float* r; // array of fiber radii 683 float* r; // array of fiber radii
700 - unsigned int n_data = network.sizeV(); //set the number of points 684 + unsigned int n_data = network.sizeAfterSamplingV(); //set the number of points
701 c = (double**) malloc(sizeof(double*) * n_data); //allocate the array pointer 685 c = (double**) malloc(sizeof(double*) * n_data); //allocate the array pointer
702 for(unsigned int i = 0; i < n_data; i++) //allocate space for each point 686 for(unsigned int i = 0; i < n_data; i++) //allocate space for each point
703 {c[i] = (double*) malloc(sizeof(double) * 3);} 687 {c[i] = (double*) malloc(sizeof(double) * 3);}
704 r = (float*) malloc(sizeof(float) * n_data); //allocate space for the radii 688 r = (float*) malloc(sizeof(float) * n_data); //allocate space for the radii
705 - stim::vec<T> node;  
706 - for(int i = 0; i < n_data; i++) 689 + //stim::vec<T> node;
  690 + for(unsigned int i = 0; i < n_data; i++)
707 { 691 {
708 - node = network.V[i].getPosition(); 692 + //node = network.V[i].getPosition();
709 //convert_to_double 693 //convert_to_double
710 for(unsigned int d = 0; d < 3; d++){ //for each dimension 694 for(unsigned int d = 0; d < 3; d++){ //for each dimension
711 - c[i][d] = double(node[d]); //copy the coordinate 695 + c[i][d] = double(network.allVerticesAfterSampling[i][d]); //copy the coordinate
712 } 696 }
713 r[i] = r[i]; //copy the radius 697 r[i] = r[i]; //copy the radius
714 } 698 }
@@ -731,54 +715,38 @@ class network{ @@ -731,54 +715,38 @@ class network{
731 { 715 {
732 V.push_back(nodes); 716 V.push_back(nodes);
733 } 717 }
734 - ///exports the graph.  
735 void 718 void
736 - to_csv() 719 + addVertices(std::vector< stim::vec<T> > vertices)
737 { 720 {
738 - std::ofstream ofs;  
739 - ofs.open("Graph.csv", std::ofstream::out | std::ofstream::app);  
740 - for(int i = 0; i < V.size(); i++) 721 + for (unsigned int i=0; i < vertices.size(); i ++)
741 { 722 {
742 - ofs << V[i].edges_to_str() << "\n"; 723 + allVerticesList.push_back(vertices[i]);
743 } 724 }
744 - ofs.close();  
745 } 725 }
746 -  
747 - ///exports the graph.  
748 void 726 void
749 - to_gdf() 727 + addVerticesAfterSamplimg(std::vector< stim::vec<T> > vertices)
750 { 728 {
751 - std::ofstream ofs;  
752 - ofs.open("Graph.gdf", std::ofstream::out | std::ofstream::app);  
753 - ofs << "nodedef>name VARCHAR\n";  
754 - for(int i = 0; i < V.size(); i++) 729 + for (unsigned int i=0; i < vertices.size(); i ++)
755 { 730 {
756 - ofs << i << "\n"; 731 + allVerticesAfterSampling.push_back(vertices[i]);
757 } 732 }
758 - ofs << "edgedef>Nodes[1] VARCHAR, Nodes[2] VARCHAR, weight INT, length FLOAT, av_radius FLOAT \n";  
759 - for(int i = 0; i < E.size(); i++)  
760 - {  
761 - ofs << E[i]->Nodes[1] << "," << E[i]->Nodes[2] << "," <<E[i]->n_pts()  
762 - << ","<< E[i]->length() << "," << E[i]->average_radius() << "\n";  
763 - }  
764 - ofs.close();  
765 } 733 }
766 // gaussian function 734 // gaussian function
767 float gaussianFunction(float x, float std=25) 735 float gaussianFunction(float x, float std=25)
768 { 736 {
769 - float normalization = multfactor * std;  
770 - float evaluate = 1.0 - (exp(-x/(2*std*std))); 737 + float evaluate = 1.0f - ((exp(-x/(2*std*std))));
771 return evaluate; 738 return evaluate;
772 } 739 }
  740 + // compares point on a network to a kd tree for two skeletons
773 boost::tuple< float, float > 741 boost::tuple< float, float >
774 - compareSkeletons(boost::tuple< ANNkd_tree*, ANNkd_tree*, stim::network<int>, stim::network<int> > networkKdtree) 742 + compareSkeletons(boost::tuple< ANNkd_tree*, ANNkd_tree*, stim::network<float>, stim::network<float> > networkKdtree)
775 { 743 {
776 float gFPR, gFNR; 744 float gFPR, gFNR;
777 gFPR = CompareNetKD(networkKdtree.get<0>(), networkKdtree.get<3>()); 745 gFPR = CompareNetKD(networkKdtree.get<0>(), networkKdtree.get<3>());
778 gFNR = CompareNetKD(networkKdtree.get<1>(), networkKdtree.get<2>()); 746 gFNR = CompareNetKD(networkKdtree.get<1>(), networkKdtree.get<2>());
779 return boost::make_tuple(gFPR, gFNR); 747 return boost::make_tuple(gFPR, gFNR);
780 } 748 }
781 - // gaussian distance of points on network to Kdtree 749 + // gaussian distance of points on network to Kdtree
782 float 750 float
783 CompareNetKD(ANNkd_tree* kdTreeGroundtruth, stim::network<T> networkTruth) 751 CompareNetKD(ANNkd_tree* kdTreeGroundtruth, stim::network<T> networkTruth)
784 { 752 {
@@ -793,14 +761,14 @@ class network{ @@ -793,14 +761,14 @@ class network{
793 float totalNetworkLength = networkTruth.lengthOfNetwork(); 761 float totalNetworkLength = networkTruth.lengthOfNetwork();
794 stim::vec<float> fiberMetric(networkTruth.sizeE()); 762 stim::vec<float> fiberMetric(networkTruth.sizeE());
795 //for each fiber 763 //for each fiber
796 - for (unsigned i=0; i < networkTruth.sizeE(); i ++) 764 + for (unsigned int i=0; i < networkTruth.sizeE(); i ++)
797 { 765 {
798 std::vector<T> p1(3); std::vector<T> p2(3);//temporary variables to store point positions 766 std::vector<T> p1(3); std::vector<T> p2(3);//temporary variables to store point positions
799 fiberPoints = networkTruth.E[i]->centerline(); 767 fiberPoints = networkTruth.E[i]->centerline();
800 N = networkTruth.E[i]->n_pts(); 768 N = networkTruth.E[i]->n_pts();
801 stim::vec<float> segmentMetric(N-1); 769 stim::vec<float> segmentMetric(N-1);
802 // for each segment in the fiber 770 // for each segment in the fiber
803 - for (unsigned j = 0; j < N - 1; j++) 771 + for (unsigned int j = 0; j < N - 1; j++)
804 { 772 {
805 ANNpoint queryPt1; queryPt1 = annAllocPt(3); 773 ANNpoint queryPt1; queryPt1 = annAllocPt(3);
806 ANNpoint queryPt2; queryPt2 = annAllocPt(3); 774 ANNpoint queryPt2; queryPt2 = annAllocPt(3);
@@ -814,14 +782,56 @@ class network{ @@ -814,14 +782,56 @@ class network{
814 } 782 }
815 kdTreeGroundtruth->annkSearch( queryPt1, 1, nnIdx1, dists1, eps); // error bound 783 kdTreeGroundtruth->annkSearch( queryPt1, 1, nnIdx1, dists1, eps); // error bound
816 kdTreeGroundtruth->annkSearch( queryPt2, 1, nnIdx2, dists2, eps); // error bound 784 kdTreeGroundtruth->annkSearch( queryPt2, 1, nnIdx2, dists2, eps); // error bound
817 - float dist1 = gaussianFunction(dists1[0]);float dist2 = gaussianFunction(dists2[0]); 785 + std::cout<<float(dists1[0])<<"dist1-----"<<float(dists2[0])<<"dist2---"<<std::endl;
  786 + float dist1 = gaussianFunction(float(dists1[0]));float dist2 = gaussianFunction(float(dists2[0]));
818 segmentMetric[j] = (((dist1 + dist2) / 2) * dist(p1, p2)) ; 787 segmentMetric[j] = (((dist1 + dist2) / 2) * dist(p1, p2)) ;
819 } 788 }
820 - fiberMetric[i] = sum(segmentMetric); 789 + fiberMetric[i] = sum(segmentMetric)/;
821 } 790 }
822 netmetsMetric = sum(fiberMetric)/totalNetworkLength ; 791 netmetsMetric = sum(fiberMetric)/totalNetworkLength ;
823 return netmetsMetric; 792 return netmetsMetric;
824 } 793 }
  794 + //resample a fiber in the network
  795 + std::vector<stim::vec<T> > Resample(std::vector< stim::vec<T> > fiberPositions, float spacing=25.0)
  796 + {
  797 + std::vector<T> p1(3), p2(3), v(3);
  798 + stim::vec<T> p(3);
  799 + std::vector<stim::vec<T> > newPointList;
  800 + for(unsigned int f=0; f<fiberPositions.size()-1; f++)
  801 + {
  802 + T lengthSegment = dist(p1,p2);
  803 + for(int d=0; d<3;d++)
  804 + {
  805 + p1[d] = T(fiberPositions[f][d]);
  806 + p2[d] = T(fiberPositions[f + 1][d]);
  807 + }// for each dimension
  808 + if( lengthSegment >= spacing )
  809 + { for (int dim=0; dim<3;dim++) //find the direction of travel
  810 + {v[dim] = p2[dim] - p1[dim];}
  811 + //set the step size to the voxel size
  812 + T step;
  813 + for(step=0.0; step<lengthSegment; step+=spacing)
  814 + {
  815 + for(int i=0; i<3;i++)
  816 + {p[i] = p1[i] + v[i]*(step/lengthSegment);}
  817 + newPointList.push_back(p);
  818 + }
  819 + }
  820 + else
  821 + newPointList = fiberPositions;
  822 + }
  823 + return newPointList;
  824 + }
  825 + // modulus of a vector
  826 + T
  827 + Length(std::vector<T> v)
  828 + {
  829 + T sum=0;
  830 + for (int i=0; i<v.size(); i++)
  831 + sum += v[i] * v[i];
  832 + return sum;
  833 + }
  834 + // function to remove characters from a string
825 void removeCharsFromString(std::string &str, char* charsToRemove ) { 835 void removeCharsFromString(std::string &str, char* charsToRemove ) {
826 for ( unsigned int i = 0; i < strlen(charsToRemove); ++i ) { 836 for ( unsigned int i = 0; i < strlen(charsToRemove); ++i ) {
827 str.erase( remove(str.begin(), str.end(), charsToRemove[i]), str.end() ); 837 str.erase( remove(str.begin(), str.end(), charsToRemove[i]), str.end() );
@@ -833,9 +843,9 @@ class network{ @@ -833,9 +843,9 @@ class network{
833 { 843 {
834 std::ofstream ofs; 844 std::ofstream ofs;
835 ofs.open("Graph.obj", std::ofstream::out | std::ofstream::app); 845 ofs.open("Graph.obj", std::ofstream::out | std::ofstream::app);
836 - int num = V.size();  
837 - string *strArray = new string[num];  
838 - for(int i = 0; i < allVerticesList.size(); i++) 846 + int num = allVerticesList.size();
  847 + std::string *strArray = new std::string[num];
  848 + for(unsigned int i = 0; i < allVerticesList.size(); i++)
839 { 849 {
840 std::string str; 850 std::string str;
841 str = allVerticesList[i].str(); 851 str = allVerticesList[i].str();
@@ -848,10 +858,44 @@ class network{ @@ -848,10 +858,44 @@ class network{
848 { 858 {
849 std::string str; 859 std::string str;
850 str = E[i]->strObj(strArray, num); 860 str = E[i]->strObj(strArray, num);
  861 + //removeCharsFromString(str,"0");
851 ofs << "l " << str << "\n"; 862 ofs << "l " << str << "\n";
852 } 863 }
853 ofs.close(); 864 ofs.close();
854 } 865 }
  866 + ///exports the graph.
  867 + void
  868 + to_csv()
  869 + {
  870 + std::ofstream ofs;
  871 + ofs.open("Graph.csv", std::ofstream::out | std::ofstream::app);
  872 + std::cout<<"here"<<std::endl;
  873 + for(int i = 0; i < V.size(); i++)
  874 + {
  875 + std::cout<<"here"<<i<<std::endl;
  876 + ofs << V[i].edges_to_str() << "\n";
  877 + }
  878 + ofs.close();
  879 + }
  880 + ///exports the graph.
  881 + void
  882 + to_gdf()
  883 + {
  884 + std::ofstream ofs;
  885 + ofs.open("Graph.gdf", std::ofstream::out | std::ofstream::app);
  886 + ofs << "nodedef>name VARCHAR\n";
  887 + for(int i = 0; i < V.size(); i++)
  888 + {
  889 + ofs << i << "\n";
  890 + }
  891 + ofs << "edgedef>Nodes[1] VARCHAR, Nodes[2] VARCHAR, weight INT, length FLOAT, av_radius FLOAT \n";
  892 + for(int i = 0; i < E.size(); i++)
  893 + {
  894 + ofs << E[i]->Nodes[1] << "," << E[i]->Nodes[2] << "," <<E[i]->n_pts()
  895 + << ","<< E[i]->length() << "," << E[i]->average_radius() << "\n";
  896 + }
  897 + ofs.close();
  898 + }
855 899
856 }; 900 };
857 }; 901 };