00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00034 #include <mtt/pmht.h>
00035
00037 tree<t_nodePtr> global_tree;
00038
00040 extern gvplugin_library_t gvplugin_xgtk_LTX_library;
00041
00043 GVGraph*graph_context;
00044
00046 Publisher markers_publisher;
00047
00049 Publisher markers_tree_publisher;
00050
00052 string tracking_frame;
00053
00055 double max_mahalanobis=7;
00056
00058 pthread_t graph_thread;
00059
00061 long iteration=0;
00062
00063
00064 void CreateTreeMarker(vector<visualization_msgs::Marker>& mrk,tree<t_nodePtr>::iterator root)
00065 {
00066 visualization_msgs::Marker marker;
00067
00068 (*root)->marker.lifetime=ros::Duration(1.0);
00069
00070
00071 (*root)->marker.header.frame_id = tracking_frame;
00072 (*root)->marker.header.stamp = ros::Time::now();
00073
00074
00075 (*root)->marker.ns = "nodes";
00076 (*root)->marker.action = visualization_msgs::Marker::ADD;
00077 (*root)->marker.pose.orientation.w = 1.0;
00078 (*root)->marker.type = visualization_msgs::Marker::TEXT_VIEW_FACING;
00079
00080 (*root)->marker.scale.x = 0.5;
00081 (*root)->marker.scale.y = 0.5;
00082 (*root)->marker.scale.z = 0.5;
00083
00084 (*root)->marker.color.r = 1.0;
00085 (*root)->marker.color.g = 0.6;
00086 (*root)->marker.color.b = 0.0;
00087 (*root)->marker.color.a = 1.0;
00088
00089 tree<t_nodePtr>::iterator parent = global_tree.parent(root);
00090 tree<t_nodePtr>::sibling_iterator sibling = root;
00091 sibling--;
00092
00093 (*root)->marker.pose.position.y = 2;
00094
00095 if(parent==0)
00096 (*root)->marker.pose.position.z = 0;
00097 else
00098 (*root)->marker.pose.position.z = (*parent)->marker.pose.position.z + 1.0;
00099
00100 if(root==global_tree.begin())
00101 (*root)->marker.pose.position.x = 0;
00102 else if(sibling==0)
00103 (*root)->marker.pose.position.x = (*parent)->marker.pose.position.x;
00104 else
00105 (*root)->marker.pose.position.x = (*sibling)->marker.pose.position.x + 1.0;
00106
00107 (*root)->marker.text = boost::lexical_cast<string>((*root)->id) + "." + boost::lexical_cast<string>((*root)->age);
00108 cout<<"Text:"<<(*root)->marker.text<<endl;
00109
00110 if(mrk.size()==0)
00111 (*root)->marker.id=0;
00112 else
00113 (*root)->marker.id = mrk[mrk.size()-1].id+1;
00114
00115 mrk.push_back((*root)->marker);
00116
00117 tree<t_nodePtr>::sibling_iterator children;
00118
00119 for(children=global_tree.begin(root);children!=global_tree.end(root);++children)
00120 {
00121 CreateTreeMarker(mrk,children);
00122 }
00123 }
00124
00125 MatrixXd EllipseParametric(Matrix2d& cov,Vector2d& mu,double MahThreshold)
00126 {
00127
00128
00129
00130
00131
00132
00133
00134 Eigen::SelfAdjointEigenSolver<Matrix2d> eigensolver(cov);
00135 if(eigensolver.info() != Eigen::Success)
00136 abort();
00137
00138 Matrix2d eigvectors=eigensolver.eigenvectors();
00139
00140 Vector2d ev1=eigvectors.row(0);
00141 Vector2d ev2=eigvectors.row(1);
00142
00143
00144 Vector2d p;
00145
00146
00147 double k_step=0.2;
00148
00149 double k=0;
00150
00151 double d;
00152
00153 double ea,eb;
00154
00155 double g;
00156
00157
00158 do
00159 {
00160 p=k*ev1+mu;
00161 k+=k_step;
00162
00163 d=Mahalanobis(p,mu,cov);
00164
00165 if(MahThreshold-d < 0.5)
00166 k_step=0.01;
00167
00168 }while(d<MahThreshold);
00169
00170 k_step=0.2;
00171 ea=k;
00172
00173 k=0;
00174 do
00175 {
00176 p=k*ev2+mu;
00177 k+=k_step;
00178
00179 d=Mahalanobis(p,mu,cov);
00180
00181 if(MahThreshold-d < 0.5)
00182 k_step=0.01;
00183
00184 }while(d<MahThreshold);
00185
00186 eb=k;
00187
00188 g=atan2(ev1(1),ev1(0));
00189
00190
00191 double t_step=0.2;
00192
00193 double t_max=2*M_PI+t_step;
00194
00195 double steps=ceil(t_max/t_step);
00196
00197 MatrixXd el(2,steps);
00198
00199 for(uint i=0;i<steps;i++)
00200 {
00201 double t=i*t_step;
00202 el(0,i)=mu(0)+ea*cos(t)*cos(g)-eb*sin(t)*sin(g);
00203 el(1,i)=mu(1)+ea*cos(t)*sin(g)+eb*sin(t)*cos(g);
00204 }
00205
00206 return el;
00207 }
00208
00209 void CreateMarkersFromTreeLeafs(vector<visualization_msgs::Marker>& marker_vector)
00210 {
00211 std_msgs::ColorRGBA color;
00212 class_colormap colormap("hsv",10, 1, false);
00213
00214 uint size_markers=0;
00215
00216 tree<t_nodePtr>::leaf_iterator leaf;
00217
00218 uint leaf_size=0;
00219 for(leaf=global_tree.begin_leaf();leaf!=global_tree.end_leaf();leaf++)
00220 leaf_size++;
00221
00222 if(marker_vector.size()<2*leaf_size+1)
00223 marker_vector.resize(2*leaf_size+1);
00224
00225 for(uint i=0;i<marker_vector.size();i++)
00226 {
00227 marker_vector[i].action=visualization_msgs::Marker::DELETE;
00228 marker_vector[i].header.frame_id=tracking_frame;
00229 }
00230
00231 visualization_msgs::Marker marker;
00232
00233 marker.lifetime=ros::Duration(1.0);
00234
00235 marker.header.frame_id = tracking_frame;
00236 marker.header.stamp = ros::Time::now();
00237
00238
00239 marker.ns = "centers";
00240 marker.action = visualization_msgs::Marker::ADD;
00241 marker.pose.orientation.w = 1.0;
00242 marker.type = visualization_msgs::Marker::POINTS;
00243
00244 marker.scale.x = 0.2;
00245 marker.scale.y = 0.2;
00246 marker.scale.z = 0.2;
00247
00248 color.r=1.0;
00249 color.g=0.6;
00250 color.b=0.1;
00251 color.a=1;
00252
00253 marker.color = color;
00254
00255 geometry_msgs::Point p;
00256
00257
00258 for(leaf=global_tree.begin_leaf();leaf!=global_tree.end_leaf();leaf++)
00259 {
00260 p.x = (*leaf)->x(0);
00261 p.y = (*leaf)->x(1);
00262 p.z = 0;
00263
00264 marker.points.push_back(p);
00265 }
00266
00267 marker.id=0;
00268 marker_vector[size_markers++]=marker;
00269
00270
00271 color.r=0.;
00272 color.g=0;
00273 color.b=0.;
00274 color.a=1;
00275
00276 marker.pose.position.z=0.3;
00277 marker.type = visualization_msgs::Marker::TEXT_VIEW_FACING;
00278 marker.ns = "ids";
00279
00280 marker.scale.x = 0.5;
00281 marker.scale.y = 0.5;
00282 marker.scale.z = 0.5;
00283
00284 marker.color = color;
00285
00286 for(leaf=global_tree.begin_leaf();leaf!=global_tree.end_leaf();leaf++)
00287 {
00288 marker.pose.position.x=(*leaf)->x(0);
00289 marker.pose.position.y=(*leaf)->x(1);
00290
00291
00292
00293
00294
00295 marker.text = boost::lexical_cast<string>((*leaf)->id);
00296
00297 marker.id=size_markers;
00298 marker_vector[size_markers++]=marker;
00299 }
00300
00301
00302 marker.type = visualization_msgs::Marker::LINE_STRIP;
00303 marker.ns = "search areas";
00304
00305 marker.pose.position.x=0;
00306 marker.pose.position.y=0;
00307 marker.pose.position.z=0;
00308
00309 marker.scale.x = 0.05;
00310 marker.scale.y = 0.05;
00311 marker.scale.z = 0.05;
00312
00313 color.a=1;
00314
00315 for(leaf=global_tree.begin_leaf();leaf!=global_tree.end_leaf();leaf++)
00316 {
00317 switch((*leaf)->mode)
00318 {
00319 case t_node::NEW:
00320 color.r=0.;
00321 color.g=1;
00322 color.b=0.;
00323 break;
00324 case t_node::MAIN:
00325 color.r=1.;
00326 color.g=0;
00327 color.b=0.;
00328 break;
00329 case t_node::SIBLING:
00330 color.r=1.;
00331 color.g=0.5;
00332 color.b=0.;
00333 break;
00334 case t_node::FAILED:
00335 color.r=0.5;
00336 color.g=0;
00337 color.b=1.;
00338 break;
00339 case t_node::TEST:
00340 color.r=0.;
00341 color.g=0;
00342 color.b=0.;
00343 break;
00344 }
00345
00346 marker.color = color;
00347
00348 p.z = -0.2;
00349
00350 marker.points.clear();
00351
00352 Vector2d mu;
00353 Matrix2d cov;
00354
00355 mu(0)=(*leaf)->x_p(0);
00356 mu(1)=(*leaf)->x_p(1);
00357
00358 cov(0,0)=(*leaf)->P(0,0);
00359 cov(0,1)=(*leaf)->P(0,1);
00360 cov(1,0)=(*leaf)->P(1,0);
00361 cov(1,1)=(*leaf)->P(1,1);
00362
00363 MatrixXd ellipse = EllipseParametric(cov,mu,max_mahalanobis);
00364
00365 uint l;
00366 for(l=0;l<ellipse.cols();l++)
00367 {
00368 p.x = ellipse(0,l);
00369 p.y = ellipse(1,l);
00370
00371 marker.points.push_back(p);
00372 }
00373
00374 marker.id=size_markers;
00375 marker_vector[size_markers++]=marker;
00376 }
00377 }
00378
00379 void CreateMarkers(vector<visualization_msgs::Marker>& marker_vector,vector<t_clusterPtr>&clusters)
00380 {
00381 std_msgs::ColorRGBA color;
00382 class_colormap colormap("hsv",10, 1, false);
00383
00384 uint size_markers=0;
00385
00386 color.r=0.;
00387 color.g=0.2;
00388 color.b=1.;
00389 color.a=1;
00390
00391 if(marker_vector.size()<2*clusters.size()+1)
00392 marker_vector.resize(2*clusters.size()+1);
00393
00394 for(uint i=0;i<marker_vector.size();i++)
00395 {
00396 marker_vector[i].action=visualization_msgs::Marker::DELETE;
00397 marker_vector[i].header.frame_id=tracking_frame;
00398 }
00399
00400 visualization_msgs::Marker marker;
00401
00402 marker.lifetime=ros::Duration(0.2);
00403
00404 marker.header.frame_id = tracking_frame;
00405 marker.header.stamp = ros::Time::now();
00406
00407
00408 marker.ns = "clusters centers";
00409 marker.action = visualization_msgs::Marker::ADD;
00410 marker.pose.orientation.w = 1.0;
00411 marker.type = visualization_msgs::Marker::POINTS;
00412
00413 marker.scale.x = 0.2;
00414 marker.scale.y = 0.2;
00415 marker.scale.z = 0.2;
00416
00417 marker.color = color;
00418
00419 geometry_msgs::Point p;
00420
00421 for(uint i=0; i<clusters.size(); i++)
00422 {
00423 p.x = clusters[i]->centroid.x;
00424 p.y = clusters[i]->centroid.y;
00425 p.z = 0;
00426
00427 marker.points.push_back(p);
00428 }
00429
00430 marker.id=0;
00431 marker_vector[size_markers++]=marker;
00432
00433
00434 color.r=0.;
00435 color.g=0;
00436 color.b=0.;
00437 color.a=1;
00438
00439 marker.ns = "ids";
00440
00441 marker.pose.position.z=0.3;
00442
00443 marker.type = visualization_msgs::Marker::TEXT_VIEW_FACING;
00444
00445 marker.scale.x = 0.5;
00446 marker.scale.y = 0.5;
00447 marker.scale.z = 0.5;
00448
00449 marker.color = color;
00450
00451 for(uint i=0;i<clusters.size();i++)
00452 {
00453 marker.pose.position.x=clusters[i]->centroid.x;
00454 marker.pose.position.y=clusters[i]->centroid.y;
00455
00456 marker.text = boost::lexical_cast<string>(clusters[i]->id);
00457
00458 marker.id=size_markers;
00459 marker_vector[size_markers++]=marker;
00460 }
00461 }
00462
00463
00464 void PointCloud2ToVector(const sensor_msgs::PointCloud2& cloud,vector<t_pointPtr>& data)
00465 {
00466 pcl::PointCloud<pcl::PointXYZ> PclCloud;
00467
00468 pcl::fromROSMsg(cloud,PclCloud);
00469
00470 double theta;
00471 map<double,pair<uint,double> > grid;
00472 map<double,pair<uint,double> >::iterator it;
00473
00474 double spacing = 1.*M_PI/180.;
00475
00476 double rightBorder;
00477 double leftBorder;
00478
00479 double r;
00480
00481
00482 for(uint i=0;i<PclCloud.points.size();i++)
00483 {
00484 theta=atan2(PclCloud.points[i].y,PclCloud.points[i].x);
00485 r=sqrt(pow(PclCloud.points[i].x,2)+pow(PclCloud.points[i].y,2));
00486
00487
00488 rightBorder = spacing * ceil(theta/spacing);
00489 leftBorder = rightBorder - spacing;
00490
00491 if(fabs(rightBorder-theta)<fabs(leftBorder-theta))
00492 theta=rightBorder;
00493 else
00494 theta=leftBorder;
00495
00496 if(grid.find(theta)!=grid.end())
00497 {
00498 if(grid[theta].second>r)
00499 {
00500 grid[theta].first=i;
00501 grid[theta].second=r;
00502 }
00503 }else
00504 {
00505 grid[theta].first=i;
00506 grid[theta].second=r;
00507 }
00508 }
00509
00510 uint i=0;
00511 for(it=grid.begin();it!=grid.end();it++)
00512 {
00513 t_pointPtr pt(new t_point);
00514
00515 pt->x=PclCloud.points[(*it).second.first].x;
00516 pt->y=PclCloud.points[(*it).second.first].y;
00517 pt->r=sqrt(pow(pt->x,2)+pow(pt->y,2));
00518 pt->t=atan2(pt->y,pt->x);
00519 pt->n=i++;
00520
00521 data.push_back(pt);
00522 }
00523 }
00524
00525 void CreateObjects(vector<t_pointPtr>&data,vector<t_clusterPtr>&clusters,double clustering_distance)
00526 {
00527 static double id=0;
00528
00529 vector<t_pointPtr>::iterator p1;
00530 vector<t_pointPtr>::iterator p2;
00531
00532 double dist;
00533 t_clusterPtr cls;
00534
00535 for(p1=data.begin();p1!=data.end();p1++)
00536 {
00537
00538
00539 if((*p1)->cl.use_count()==0)
00540 {
00541
00542 cls.reset(new t_cluster);
00543 cls->id=id++;
00544
00545 clusters.push_back(cls);
00546
00547 (*p1)->cl=cls;
00548
00549 cls->points.push_back(*p1);
00550 }
00551
00552 for(p2=data.begin();p2!=data.end();p2++)
00553 {
00554 if((*p2)->cl.use_count()==0)
00555 {
00556 dist=Euclidean_distance(*(*p1),*(*p2));
00557 if(dist<clustering_distance)
00558 {
00559 (*p1)->cl->points.push_back(*p2);
00560 (*p2)->cl=(*p1)->cl;
00561 }
00562 }
00563 }
00564 }
00565
00566 vector<t_clusterPtr>::iterator it;
00567
00568 for(it=clusters.begin();it!=clusters.end();it++)
00569 (*it)->CalculateCentroid();
00570 }
00571
00572 double Mahalanobis(Vector2d&y,Vector2d&mean,Matrix2d& cov)
00573 {
00574 VectorXd a=y-mean;
00575 MatrixXd i= cov.inverse();
00576 double squared=a.transpose()*i*a;
00577 return sqrt(squared);
00578 }
00579
00580 double Mahalanobis_distance(t_nodePtr&node,t_clusterPtr&cluster)
00581 {
00582
00583 Vector2d measurement;
00584 Vector2d mean;
00585 Matrix2d covariance;
00586 measurement(0)=cluster->centroid.x;
00587 measurement(1)=cluster->centroid.y;
00588
00589 mean(0)=node->x_p(0);
00590 mean(1)=node->x_p(1);
00591
00592 covariance(0,0)=node->P(0,0);
00593 covariance(0,1)=node->P(0,1);
00594
00595 covariance(1,0)=node->P(1,0);
00596 covariance(1,1)=node->P(1,1);
00597
00598 return Mahalanobis(measurement,mean,covariance);
00599 }
00600
00601 vector<t_clusterPtr>::iterator GetClosestCandidate(t_nodePtr&node,vector<t_clusterPtr>&clusters)
00602 {
00603 vector<t_clusterPtr>::iterator it;
00604 vector<t_clusterPtr>::iterator it_min=clusters.end();
00605
00606 double distance;
00607 double min=max_mahalanobis;
00608
00609 for(it=clusters.begin();it<clusters.end();it++)
00610 {
00611 distance=Mahalanobis_distance(node,*it);
00612 if(distance<min)
00613 {
00614 it_min=it;
00615 min=distance;
00616 }
00617 }
00618
00619 return it_min;
00620 }
00621
00622 vector<vector<t_clusterPtr>::iterator> GateMeasurements(t_nodePtr&node,vector<t_clusterPtr>&clusters, double max_gating)
00623 {
00624 vector<vector<t_clusterPtr>::iterator> positions;
00625 vector<t_clusterPtr>::iterator it;
00626
00627 double gating_distance;
00628
00629
00630 for(it=clusters.begin();it<clusters.end();it++)
00631 {
00632 gating_distance=Mahalanobis_distance(node,*it);
00633 if(gating_distance<max_gating)
00634 positions.push_back(it);
00635 }
00636
00637 return positions;
00638 }
00639
00640 void ReAgeTree(void)
00641 {
00642 tree<t_nodePtr>::iterator it;
00643
00644 for(it=global_tree.begin();it!=global_tree.end();it++)
00645 (*it)->IncreaseAge();
00646 }
00647
00656 void RemoveOld(int size)
00657 {
00658 tree<t_nodePtr>::iterator it;
00659 tree<t_nodePtr>::iterator it_next;
00660 tree<t_nodePtr>::iterator it_child;
00661
00662 for(it=global_tree.begin();it!=0;it=global_tree.next_at_same_depth(it))
00663 {
00664 it_next=global_tree.next_at_same_depth(it);
00665
00666 if(it_next==0)
00667 break;
00668
00669 if(global_tree.max_depth(it)>=size)
00670 {
00671 it_child=it.node->first_child;
00672 global_tree.move_ontop_same_branch(it,it_child);
00673 it=it_child;
00674 }
00675 }
00676 }
00677
00678 void nthPruning(int size)
00679 {
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704 }
00705
00711 void DataHandler(const sensor_msgs::PointCloud2& msg)
00712 {
00713 iteration++;
00714
00715 vector<t_pointPtr> raw_points;
00716 vector<t_pointPtr>::iterator raw_it;
00717
00718 vector<t_clusterPtr> clusters;
00719 vector<t_clusterPtr>::iterator clusters_it;
00720
00721 static visualization_msgs::MarkerArray markersMsg;
00722 static visualization_msgs::MarkerArray markersTreeMsg;
00723
00724 tracking_frame=msg.header.frame_id;
00725
00726
00727
00728
00730 PointCloud2ToVector(msg,raw_points);
00731
00733 CreateObjects(raw_points,clusters,1.5);
00734
00735 tree<t_nodePtr>::leaf_iterator leaf;
00736 tree<t_nodePtr>::leaf_iterator leaf_next;
00737 tree<t_nodePtr>::leaf_iterator leaf_aux;
00738
00739 global_tree.ready_from_draw=false;
00740 global_tree.need_layout=true;
00741
00742 for(leaf=global_tree.begin_leaf();leaf!=global_tree.end_leaf();)
00743 {
00744 leaf_next=leaf;
00745 leaf_next++;
00746 vector<vector<t_clusterPtr>::iterator> gated_measurements;
00747
00748 gated_measurements = GateMeasurements(*leaf,clusters,max_mahalanobis);
00749
00750
00751
00752 if(gated_measurements.size()!=0)
00753 {
00754
00755
00756
00757 cout<<"Number of associations: "<<gated_measurements.size()<<endl;
00758 for(uint i=0;i<gated_measurements.size();i++)
00759 {
00760
00761 t_nodePtr new_leaf(new t_node(*(*leaf),*(*gated_measurements[i]),iteration));
00762 global_tree.append_child(leaf,new_leaf);
00763 }
00764
00765 }else
00766 {
00767
00768 t_nodePtr new_leaf(new t_node(*(*leaf),iteration));
00769
00770
00771
00772 if(new_leaf->failed_associations_counter>5)
00773 {
00774 leaf_aux=leaf;
00775 leaf--;
00776 global_tree.erase_branch(leaf_aux);
00777 }else
00778 {
00779 global_tree.append_child(leaf,new_leaf);
00780 leaf++;
00781 }
00782 }
00783
00784 leaf=leaf_next;
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813 }
00814
00815
00816 for(clusters_it=clusters.begin();clusters_it!=clusters.end();clusters_it++)
00817 {
00818 if( (*clusters_it)->associations.size()==0)
00819 {
00821 t_nodePtr node(new t_node( *(*clusters_it),iteration));
00823 global_tree.insert(global_tree.begin(),node);
00824 }
00825 }
00826
00827
00828 ReAgeTree();
00829
00830 RemoveOld(10);
00831
00832
00833
00834 CreateMarkers(markersMsg.markers,clusters);
00835 markers_publisher.publish(markersMsg);
00836
00837
00838 CreateMarkersFromTreeLeafs(markersTreeMsg.markers);
00839 markers_tree_publisher.publish(markersTreeMsg);
00840
00841
00842
00843 global_tree.ready_from_draw=true;
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856 }
00857
00858 void*GraphicalThread(void*data)
00859 {
00860
00861
00862
00863
00864
00865 graph_context=new GVGraph("graph");
00866
00867 gvconfig_plugin_install_from_library(graph_context->getGVCcontext(), NULL, &gvplugin_xgtk_LTX_library);
00868
00869
00870
00871
00872
00873
00874 graph_context->applyLayout();
00875 graph_context->startRender();
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890 delete graph_context;
00891
00892 return NULL;
00893 }
00894
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904
00905
00906
00907
00908
00909
00910
00911
00912
00913
00914
00915
00916
00917
00918
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942 int main(int argc,char**argv)
00943 {
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955
00956
00957
00958
00959
00960
00961
00962
00963
00964
00965
00966 init(argc,argv,"mtt");
00967
00968 NodeHandle nh("~");
00969
00970 Subscriber data_handler = nh.subscribe("/points", 1000, DataHandler);
00971
00972 markers_publisher = nh.advertise<visualization_msgs::MarkerArray>("/markersClusters", 1000);
00973
00974 markers_tree_publisher = nh.advertise<visualization_msgs::MarkerArray>("/markersTree", 1000);
00975
00976 cout<<"Subscribed to "<<names::remap("/points")<<endl;
00977 cout<<"Spinning"<<endl;
00978
00979
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014
01015
01016
01017
01018
01019
01020
01021
01022
01023
01024
01025
01026
01027
01028
01029
01030
01031
01032
01033
01034
01035
01036
01037
01038
01039
01040 kptree::print_tree_bracketed<t_nodePtr>(global_tree);
01041
01042 pthread_create( &graph_thread, NULL, GraphicalThread,NULL);
01043
01044 spin();
01045
01046
01047
01048
01049
01050
01051
01052
01053
01054
01055
01056
01057
01058
01059
01060
01061
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071
01072
01073
01074
01075
01076
01077
01078
01079
01080
01081
01082
01083
01084
01085
01086
01087
01088
01089
01090
01091
01092
01093
01094
01095
01096
01097
01098
01099
01100
01101
01102
01103
01104
01105
01106
01107
01108
01109
01110
01111
01112
01113
01114
01115
01116
01117
01118
01119
01120
01121
01122
01123
01124
01125
01126
01127
01128
01129
01130
01131
01132
01133
01134
01135
01136
01137
01138
01139
01140
01141
01142
01143
01144
01145
01146
01147
01148
01149
01150
01151
01152
01153
01154
01155
01156
01157 return 0;
01158 }